24. 【C语言】删除单链表中的重复元素(5_task)

问题说明:
因为是删除的是单链表中的重复元素,这和删除单链表中值为x的元素有区别。例如给出一组数:1 2 2 3。前者得到的结果是1 2 3;后者删除2,得到1 3。

算法思想:
本算法适用于事先所得到的单链表中元素是有序的,即元素值按大小排好序的。假设任意输入一组数,通过单链表的有序插入生成单链表,这样,重复的元素必然相邻。只要链表不为空,首结点肯定是不会动的。定义3个结点指针:ppre、pcur、pdel,pcur作为活动指针,初始指向第二个结点,而ppre初始指向pcur的前驱结点,pdel用于指向待删除的结点。用一个循环控制ppre和pcur向后偏移,当ppre指向的结点值和pcur指向的结点值相等,那么ppre的指向的位置保持不动,将pcur的指向先传递给pdel,然后pcur向后移一个位置,再将ppre指向的结点作为pcur指向的结点的前驱,这两个结点再次保持相邻,最后释放pdel指向结点的空间,达到删除的效果,如果后面还有和ppre指向的结点值相同的结点,便通过循环重复执行这些操作。循环执行的过程中ppre就相当于一个基准,不会发生移动。只有当ppre指向的结点值和此时pcur指向的结点值不相等时,ppre才会向后偏移一个位置,而pcur就指向ppre指向位置的下一个位置。
可以通过如下图理解ppre和pcur指向位置的轨迹变化:
在这里插入图片描述
案例效果:
在这里插入图片描述
链表中各结点之间的连接关系变化:
在这里插入图片描述
删除链表中的重复元素之后
在这里插入图片描述
完整代码如下:

#include<stdio.h>
#include<stdlib.h>
typedef struct linklist {
	int data;
	struct linklist *next;
}list,*plist;

void list_create(plist *pphead, plist *pptail, int key)
{
	plist pnew = (plist)calloc(1, sizeof(list));
	pnew->data = key;
	if (NULL == *pphead)
	{
		*pphead = pnew;
		*pptail = pnew;
	}
	else if (pnew->data <= (*pphead)->data)
	{
		pnew->next = *pphead;
		*pphead = pnew;
	}
	else if (pnew->data > (*pphead)->data && pnew->data <= (*pptail)->data)
	{
		plist ppre=*pphead, pcur = (*pphead)->next;
		while (pcur)
		{
			if (pnew->data > ppre->data && pnew->data <= pcur->data)
			{
				pnew->next = pcur;
				ppre->next = pnew;
			}
			ppre = pcur;
			pcur = pcur->next;
		}
	}
	else {
		(*pptail)->next = pnew;
		*pptail = pnew;
	}
}

void del_node(plist *pphead)
{
	if (NULL == *pphead)
		printf("linklist is empty\n");
	else {
		plist ppre=*pphead, pcur = (*pphead)->next,pdel;
		while (pcur)
		{
			if (ppre->data == pcur->data)
			{
				pdel = pcur;
				pcur = pdel->next;
				ppre->next = pcur;
				free(pdel);
			}
			else {
				ppre = ppre->next;
				pcur = ppre->next;
			}
		}
	}
}

void list_print(plist phead)
{
	while (phead)
	{
		printf("%d ", phead->data);
		phead = phead->next;
	}
	printf("\n");
}

int main()
{
	plist phead = NULL, ptail = NULL;
	int key;
	while (scanf("%d", &key) != EOF)
	{
		list_create(&phead, &ptail, key);
	}
	del_node(&phead, &ptail);
	list_print(phead);
	system("pause");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值