(不带头结点的)单链表增删查改,逆置单链表(两种方法),求两个单链表的第一个公共结点,合并两个单链表,单循环链表中判断第一个入环点,约瑟夫环

本文详细介绍了单链表的各种基本操作实现,包括增删查改、逆置、合并及特殊场景应用等,并提供了完整的源代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

补充了每个算法的基本思想,并且画了思路图,源代码都经过调试成功

1.SlistNode.c文件

(1) (不带头结点的)单链表增删查改

 #include "SlistNode.h"

SlistNode* slistBuyNode(int x)  //申请新的值为x的节点
{
	SlistNode *t = (SlistNode*)malloc(sizeof(SlistNode));
	t->data = x;
	t->next = NULL;
	return t;
}

void slistInit(SlistNode **p)   //初始化
{
	(*p)= NULL;
}

void slistPrint(SlistNode*p)   //打印
{
	SlistNode* t = p;
	for (t = p; t; t = t->next)
	{
		printf("%d->", t->data);
	}
	printf("NULL\n");
}
SlistNode* slistFind(SlistNode*p, int x)  //查找x
{
	SlistNode* t = p;
	for (t = p; t; t = t->next)
	{
		if (t->data == x)
			return t;
	}
	return NULL;
}

void slistInsert(SlistNode**pos, int x) //在pos后插入
{
	SlistNode*t = slistBuyNode(x);
		t->next = (*pos)->next;
		(*pos)->next = t;
}

void slistEraseAfter(SlistNode**p,int x)   //删除x
{
	SlistNode*t = *p,*t1;
	if ((*p)->data == x) //要删除的值x是第一个结点时
	{
		t1 = *p; //临时备份
		*p = t1->next;
		free(t1);
		t1 = NULL;
	}
	for (t = *p; t&&t->next; t = t->next) //要删除的值x不是第一个结点时
	{
		if (t->next->data == x) //t->next即从第二个结点开始扫描
		{
			t1 = t->next;
			t->next = t1->next;
			free(t1);
			t1 = NULL;
		}
	}
	return 1;
}

void slistPushFront(SlistNode**p, int x) //头插
{	
	SlistNode*t = slistBuyNode(x);
	t->next = (*p);
	(*p) = t;
}

void slistPopFront(SlistNode**p) //头删
{
	SlistNode *t;
	if ((*p) == NULL)
		return;
	t = (*p)->next;
	free((*p));
	*p = t;
	return;
}

void slistDestory(SlistNode **p) //销毁
{
	SlistNode *t = *p;
	if ((*p) == NULL)
		return ;
	while ((*p)->next != NULL)
	{
		(*p)->next = (*p)->next->next;//不停地后删,直到删光所有结点
		free(*p);
		*p = NULL; //防止野指针
	}
}

void removeall(SlistNode**p, int x)  //删除所有值为X的结点
{
	SlistNode *t, *t1;
	if ((*p) == NULL)
		return NULL;
	if (((*p)->data == x)) //要删除的x是第一个结点时
	{
		t = (*p);t1 = t;
		*p =t1->next;
		free(t1);
		t1 = NULL;
	}
	t = *p; //执行完上述操作之后t指向的原来的*p被释放了,所以要让t指向新的头
	while (t->next&&t)  //这里用一个while和if-else循环将从第二个结点开始的所有与
	{                   //x相同的结点删除。
			if (t->next->data == x) //t->next即从第二个结点开始扫描
			{
				t1 = t->next;
				t->next = t1->next;
				free(t1);
				t1 = NULL;
			}
			else
				t = t->next;
	}		
}

(2)逆置单链表(两种方法)

方法一:先后删,别释放,再头插。具体可以如下图所示。

在这里插入图片描述

void reverse1(SlistNode**p)  //逆置单链表
{
	SlistNode*t;   //当前操作的结点
	SlistNode*h;  //指向新的头结点
	SlistNode*oldh; //一直指向旧的头结点
	oldh = *p;
	h = oldh;
	t = oldh->next;
	while(t)
	{
		oldh->next = t->next; //后删
		t->next = h;    //头插
		h = t;
		t = oldh->next;
	}
	*p = h;  // 最后的新头是h
}

方法二:断结点,向后转,具体如图:

在这里插入图片描述

void reverse2(SlistNode**p)   //逆置单链表2

{
	SlistNode*h, *c, *t;
	h = *p;
	c = h->next;
	t = c;
	h->next = NULL;
	while (t)
	{
		t = t->next;
		c->next = h;
		h = c;
		c = t;
	}
	*p = h;
}

(3)求两个单链表的第一个公共结点

在这里插入图片描述

int comnode(SlistNode**LA, SlistNode**LB)   //两个链表公共结点
{
	SlistNode*A = *LA, *B = *LB;
	int lenA = 0, lenB = 0,gap=0;
	for (A = *LA; A; A = A->next)
		lenA++;
	for (B = *LB; B; B = B->next)
		lenB++;
	A = *LA;  B = *LB;  //上述操作之后A与B的指向均已发生变化。
	gap = abs(lenA - lenB);
	if (lenB > lenA)
	{
		A = *LB;
		B = *LA;
	}
	for (int i = 0; i < gap; i++)
		A = A->next;
	for (; A&&B; A = A->next, B = B->next)
		if (A->data == B->data)  //这里不能是两个指针变量比较
			return A->data;
	return NULL;
}

(4)合并两个单链表

在这里插入图片描述

SlistNode* merge(SlistNode**LA, SlistNode**LB)  //合并两个单链表
{
	SlistNode*preA = *LA, *L = preA,*A = preA->next, *B = *LB, *nextB = B->next;
	while( preA&&A&&nextB&&B)
	{
		if (preA->data > B->data)
		{
			B->next = preA; //插入
			B = nextB;
			nextB = B->next; 
		}
		if (A->data > B->data)
		{
			B->next = A;
			preA->next = B; //插入B
			preA = B;  //插入的B在preA和A之间
			B = nextB;
			nextB = nextB->next;
		}
		else if (A->data <= B->data)
		{
			preA = A;
			A=preA->next;
		}
	}
	while (nextB)//A为空且B不为空时
	{
		A->next = B;
		B = nextB;
	}
	free(B);
	B = NULL;
	return L;
}

(5)单循环链表中判断第一个入环点

在这里插入图片描述
在这里插入图片描述

SlistNode* cycle(SlistNode**h) //单循环链表中判断第一个入环点
{
	SlistNode*fast=*h, *slow=fast;
	while (fast&&slow) //找相遇点
	{
		fast = fast->next->next;
		slow = slow->next;
		if (fast == slow)
			break;
	}
	for (; fast->next && (*h)->next; fast = fast->next, (*h) = (*h)->next)
		if (fast == *h)
			return fast;
	return NULL;
}

(6)约瑟夫环


SlistNode* Josephus(SlistNode**l,int n,int m) //约瑟夫环
{
	SlistNode *p, *prep;
	p = *l; prep = p;
	while (p->next!= *l)
	{
		p = p->next;  //p指向尾结点
	}
	prep = p;  //prep指向尾结点
	p = p->next;  //p指向第一个结点
	while (p&&prep&&n>1)
	{
		for (int i = 0; i < m-1; i++)  //从第一个结点开始报数,则报到第m个结点时,走了m-1步
		{
			prep = p;
			p = p->next;
		}
		prep->next = p->next;
		free(p);
		p=prep;
		p = p->next;
		n--;
	}
	return p;
}

**

2.SlistNode.h文件

**

#ifndef _SLISTNODE_H_
#define _SLISTNODE_H_

#include <stdio.h>
#include<windows.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>

typedef struct SlistNode
{
	int data;
	struct SlistNode* next;
}SlistNode;
void slistPrint(SlistNode *p);
void slistInit(SlistNode **p);
void slistDestory(SlistNode **p);
SlistNode* slistBuyNode(int x);

void slistPopFront(SlistNode**p);
void slistPushFront(SlistNode**p, int x);

SlistNode* slistFind(SlistNode*p, int x);

void slistInsert(SlistNode**pos,int x);
void slistEraseAfter(SlistNode**p,int x);

void removeall(SlistNode**p, int x);

void reverse1(SlistNode**p);
void reverse2(SlistNode**p);

int comnode(SlistNode**LA, SlistNode**LB);
SlistNode* cycle(SlistNode**h);
SlistNode* merge(SlistNode**LA, SlistNode**LB);
SlistNode* Josephus(SlistNode**l, int n, int m);
#endif

3.main.c文件

#include "SlistNode.h"
int main()
{
	SlistNode *p;
	slistInit(&p);
	slistPushFront(&p, 10);
	slistPushFront(&p, 9);
	slistPushFront(&p, 6);
	slistPushFront(&p, 5);
	slistPushFront(&p, 4);
	slistPushFront(&p, 1);
	

	//slistPopFront(&p);
	//slistInsert(&(p->next->next), 9);
	slistPrint(p);
	//slistEraseAfter(&p,3);
	//SlistNode*t = slistFind(p, 3);   printf("%d", t->data);
	//removeall(&p, 3);
	//reverse1(&p);
	//reverse2(&p);

/*	SlistNode *q;
	slistInit(&q);
	slistPushFront(&q, 10);
	slistPushFront(&q, 9);
	slistPushFront(&q, 8);
	slistPushFront(&q, 7);
	slistPrint(q);*/

	/*int r=comnode(&p, &q);
	printf("%d\n", r);*/


	
   SlistNode*r=p, *h;
	while (r->next)
		r = r->next;
	r->next = p;  //围成一个循环圈:1-2-3-4-5-1-2-3-4-5-1-2-3-4-5...... 
	//r->next = p->next;  第一个结点在外边,其他结点围成循环:1-2-3-4-5-2-3-4-5-2-3-4-5....
    //slistPrint(p);
	/*h=cycle(&p);
	printf("%d\n", h->data); */

	//SlistNode*t=Josephus(&p, 6, 3);
	//slistPrint(t);


	//SlistNode*t=merge(&p, &q);
	//slistPrint(t);

	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值