练习题-删除有序单链表中的重复元素(C语言实现)
一、题目
如题所述,是对单链表进行操作,而且链表是有序的,意味着重复元素都是挨在一块儿的,如下图所示:
或者是这样的:
二、思路
既然重复元素都是连续挨着的,那么我们可以设置一个快慢指针,用temp指向上一个元素的值,p指向当前元素,如果p所指和temp所指元素相等,那么把p所指的结点删除,temp保持不动,p指针后移;如果p所指和temp所指元素不等,那么temp向后移动,即temp等于p,然后再把p后移,直到p指向单链表的末尾。如下图:
三、代码实现
bool Del_duplicate(LinkList *B)
{
LinkList *q,*temp;
q = B->next;
temp = q;//temp是慢指针,指向q的前驱
q = q->next;//q往后移动
while(q->next!=NULL)
{
if(q->data == temp->data)//如果p当前指向的元素和前面的结点元素相同则删除p所指结点
temp->next = q->next;//执行删除操作
else
temp = q;//如果不等则更新temp,并且p继续向后移动,直到链表末尾
q = q->next;//q向后移动
}
return true;
}
这种方法实现显然比较简单,当然也还有别的方法,但是我这种方法空间复杂度为O(1),时间复杂度也只是为O(n),也还算不错了。
四、全部代码
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h> //根据C99标准,C语言使用bool类型需要添加这个头文件
typedef int ElemType;
typedef struct LinkNode
{
ElemType data;
struct LinkNode *next;
}LinkList;
//------------ 函数声明 ----------//
void MainMenu();
bool InitLinkList(LinkList *B);//初始化
bool InsertLinkList(LinkList *B,ElemType e);//插入
void PrintAll(LinkList *B);//输出所有元素
bool Del_duplicate(LinkList *B);//删除重复元素
//------------ 函数声明 ----------//
int main()
{
LinkList B;
int ch;
ElemType element;
if(InitLinkList(&B))
printf("初始化成功!\n");
else
printf("初始化失败!\n");
while(1)
{
MainMenu();
printf("请输入您要执行的操作:");
scanf("%d",&ch);
switch(ch)
{
case 0: printf("感谢使用,已退出!"); exit(0); break;
case 1: printf("请输入您要插入的元素:\n");
scanf("%d",&element);
if(InsertLinkList(&B,element))
printf("插入成功!\n");
else
printf("插入失败!\n");
break;
case 2: PrintAll(&B);
break;
case 3: if(Del_duplicate(&B))
printf("删除成功!\n");
else
printf("删除失败!\n");
break;
default: printf("您输入的操作指令有误!请重新输入!");
}
}
return 0;
}
//主菜单,显示
void MainMenu()
{
printf("\n\n\n");
printf("\t **** 删除有序单链表中的重复元素 ****\n\n");
printf("\t ------- 0.退出 \n\n");
printf("\t ------- 1.插入元素\n\n");
printf("\t ------- 2.输出所有元素\n\n");
printf("\t ------- 3.删除重复元素\n\n");
printf("\t *************************************\n");
}
//初始化单链表(带头结点)
bool InitLinkList(LinkList *B)
{
//先申请一个头结点
LinkList *head = (LinkList *)malloc(sizeof(LinkList));
B->next = head;
head->next = NULL;//头结点之后一开始还没元素
return true;
}
//插入
bool InsertLinkList(LinkList *B,ElemType e)
{
//头插法
LinkList *p = B;//
//申请一个新的结点
LinkList *s = (LinkList *)malloc(sizeof(LinkList));
s->data = e;//赋值
//修改指针 将结点s插入到结点p之后
s->next = p->next;//s指针指向
p->next = s;
return true;
}
void PrintAll(LinkList *B)
{
LinkList *q;
q = B->next;
//打印出所有元素
while(q->next!=NULL)
{
printf("%d ",q->data);
q = q->next;
}
}
bool Del_duplicate(LinkList *B)
{
LinkList *q,*temp;
q = B->next;
temp = q;//temp是慢指针,指向q的前驱
q = q->next;//q往后移动
while(q->next!=NULL)
{
if(q->data == temp->data)//如果p当前指向的元素和前面的结点元素相同则删除p所指结点
temp->next = q->next;//执行删除操作
else
temp = q;//如果不等则更新temp,并且p继续向后移动,直到链表末尾
q = q->next;//q向后移动
}
return true;
}
五、测试
输入得到一个序列:
执行删除操作之后再查看结果:
结束。