单链表知识汇总

数据结构入门,单链表的尾插

  1. 当链表为空时
  2. 当链表不为空时
    第一种情况,当p为空时,
    在这里插入图片描述
    第二种情况:
    当链表不为空时
    在这里插入图片描述
if(p=NULL)
plist->head =s;
else
{
	while(p-next!=NULL)
		p=p->next;
	p->next=s;
}

链表的头插

在这里插入图片描述
代码的实现

SListNode* s = _Buynode();
	s->data = x;
	s->next = plist->head;
	plist->head = s;

链表尾部删除

在这里插入图片描述
注意:释放malloc生成的堆空间时,内存空间一直都是在的,不是说你释放之后,它就不在了哈!!!只是这块内存空间现在不归你使用了而已。
调试的过程中 data,next会变成随机值,代表了data,next*其实都已经不存在了哈!!

代码如下

if(p!=NULL)
{
	if(p->next==NULL)
		free(plist->head);
		plist->head =NULL;
	else
	{
		SListNode *pre=NULL;
		while(p->next !=NULL)
		{
			pre =p;
			p=p->next;
		}
		pre->next=NULL;
		free(p);
		p=NULL;
	}
}

链表头部删除

在这里插入图片描述

链表的按值删除

按值删除,前提是要寻找到某个元素,如果找不到该元素的话,就无法删除,所以大的来说:分为2个思路:

  • 1.当要删除的元素没有时
  • 2.当要删除的元素存在于链表中时。
    • 2.1被删除的元素位于结点中间
    • 2.2被删除的元素位于结点起始位置。

代码如下所示:

SListNode *p = plist->head;
SListNode *pre = NULL;
while (p != NULL && p->data != key)
	{
		
		pre = p;
		p = p->next;
	}
if (p != NULL)
	{
		if (pre == NULL)
			plist->head = p->next;
		else
			pre->next = p->next;
		free(p);
	}

分析:删除的前提是查找到元素,我们依次遍历链表,这里有个很隐晦的地方需要注意,就是while循环的判断条件,p!=NULL&&p->data !=key,这里千万不能调换顺序,因为如果找不到该元素的话,程序就会崩溃掉。
主要是因为:与连接符连接多个条件进行判断时,(以两个条件为例)当前一个条件为假,后一个就不会进行判断。
如果被查找的元素没有的话,p一直向后移动,那么查找完所有的元素,p此时等于NULL,不满足while的循环条件,那么p->data !=KEY就不会执行。而如果调换两个的顺序,p为NULL,根本不存在data,程序就会崩溃,提示无法写入数据到0x00000000处。这是需要注意的第一个点。
其次,以下图为例,要删除的元素为3,那么我们需要定义前驱指针pre,使得2和4进行相连。
如下图所示:考虑的情况为要删除的结点为中间的结点;
而如果被删除的结点为第一个结点的话,while循环一次都不会进入,那么pre=NULL,则pre就不能解引用,所以程序会崩溃。我们只需令plist->head=p->next即可删除第一个结点。(这里不可用p=p->next;因为p和plist->head虽然指向同一块空间,但是现在p指向了p->next,可是plist-head里面存放的地址仍然是最初的地址,改变A里面的值并不影响B里面的值哦)
在这里插入图片描述

按值删除所有相同的元素

首先给出代码:有几个需要注意:
如果要删除的元素为1,给定的链表为1 1 2 2 3,那么删除掉 1 1 之后链表里面的元素为 2 2 3 ,找不到1,所以if条件判断的时候,一定要有p!=NULL这个条件,否则就会误认为找到1值,程序会发生崩溃。

void SlistRemoveAll(Slist* plist, ELEMTYPE key)
{
	SListNode *p = plist->head;
	//pre=NULL,不必写入循环内部,因为是删除,只需要向后遍历即可,而排序的话,因为
	//每插入1个元素,要和所有的元素都要进行比较。
	SListNode *pre = NULL;
	//头结点为空时,写在前面,这样一旦为空,就会返回。
	if (plist->head == NULL)
		return;
	while (p != NULL)
	{
		//删除一个值
		while (p != NULL && p->data != key)
		{
			pre = p;
			p = p->next;
		}
		
		if (p != NULL) //这个条件一定不能少
		{
			//要删除的元素为第一个元素
			if (pre == NULL)
			{
				plist->head = p->next;
			}
			else
			{
				pre->next = p->next;
			}
			free(p);
		}
		
		if (pre == NULL)
		{
			//要删除的元素为第一个元素,删除完毕之后,让p重新指向头结点,继续寻找。
			p = plist->head;
		}
		else
		{
			//p指向已经被删除结点的下一个结点。
			p = pre->next;
		}

	}
}

链表的按值插入

原理:原有链表为3,7,8,10,6;我们需要按值插入9,假设以从小到大的顺序进行插入,9比3大,故插入到3的后面,而9比7大,所以需要向后移动,变为3,7,9,8,10,6,因为9比8大,9向后移动一位,9比10小,将9按值插入到8和10中间。注意按值插入并不是排序。
思路:如下图所示:
在这里插入图片描述

链表的反转

void SlistReverse(Slist* plist)
{
	SListNode *p, *q;
	p = plist->head;
	q = p;
	//链表为空时,直接返回;
	if (p == NULL)
		return;
	//如果只有1个结点的话,那么没必要反转
	if (plist->head->next == NULL)
		return;
	//1.切割链表
	p = p->next;
	plist->head->next = NULL;
	//2.头部插入
	while (p!=NULL)
	{
		q = p->next;
		p->next = plist->head;
		plist->head = p;
		p = q;
	}
}

在这里插入图片描述

单链表的排序

主要需要完成三步:
1.断开第一个结点和后面的结点。
2.将后面的结点一个接一个的摘除掉
3.摘除掉之后,仿照按值插入的方式,将其插入到第一个结点的后面。
外层的while循环用来控制,让结点向后移动。内层的while循环用来控制让脱落下来的结点按照大小插入。
在这里插入图片描述

void SlistSort(Slist* plist)
{
	assert(plist);
	SListNode *p = plist->head;
	if (p == NULL)
		return;
	
	//要放到循环里面,因为每次进来的话,pre都需要置为空,从头结点开始比较。
	//SListNode *pre = NULL;
	p = plist->head->next;
	plist->head->next = NULL;
	//注意这里的顺序,放在最上面就错了,因为q里面实际上存储的是plist->head的地址,
	//所以下面p虽然向后移动了,但是q里面的地址并没改变,所以q的值和plist->head的值相等。
	SListNode *q = p;
	while (q!=NULL)
	{
		q = q->next;
		SListNode* t = plist->head;
		SListNode *pre = NULL;
		while (t != NULL && p->data > t->data)
		{
			//记录t的上一个结点
			pre = t;
			t = t->next;
		}
		if (NULL == pre)
		{
			p->next=plist->head;
			plist->head = p;
		}
		else
		{
			p->next = pre->next;
			pre->next = p;
		}
		p = q;
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值