[数据结构]有序单向链表的去重(C语言)
单向链表的去重
问题描述及分析
给定一个有序的链表,去除重复出现的元素,使每个元素只出现一次。例如一个单向链表为 1->1->2->2->3->4->4->∅ , 那么去重后得到的单向链表为 1->2->3->4->∅ 。
这里的链表保证是有序的,所以出现的重复元素都是相邻的,所以对整个链表进行一次遍历,在遍历的过程中删除这些相邻的重复元素即可。
首先,需要一个遍历指针 t 指向当前遍历到的节点,然后定义两个指针分别为 p1 和 p2,p1 指向 t 所指向的节点,而 p2 指向此时 p1 的下一个节点,如果 p2 指向节点的值与 p1 的相同,那么直接让 p1 的 next 跳过 p2 指向 p2 的 next 即可。有可能存在相邻很多个元素都相等,所以可以加一个循环,一次性删除多个和 p1 指向的节点的值相等的节点。😌
单向链表去重图解
发现相邻重复元素
p1的next跳过p2指向p2的next
free p2, p2指向当前p1的next
核心代码
//写法一
void Delete_same(Linklist *head) {
Linklist *t = head->next; //t遍历指针
while (t != NULL) {
Linklist *p1 = t; //p1指向t的位置
Linklist *p2 = t->next; //p2指向p1之后的位置
//p1和p2永远是相邻的
while (p2 != NULL) {
//删除的永远是p2指向的节点
if (p1->data == p2->data) {
p1->next = p2->next; //p1的next跨过删除的指向之前p2的next
free(p2);
p2 = p1->next; //p2再次指向p1的next
} else {
p1 = p1->next; //两个指针同时往后移
p2 = p2->next;
}
}
t = t->next;
}
}
//写法二
ListNode* deleteDuplicates(ListNode* head) {
if(!head) return head;
ListNode *t = head;
while(t && t->next){
if(t->val == t->next->val){
ListNode *tmp = t->next;
t->next = tmp->next;
delete tmp;
}
else
t = t->next;
}
return head;
}
完整程序
完整程序源代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int Elemtype; //数据类型
typedef struct Node {
Elemtype data; //结构体数据域
struct Node *next; //结构体指针域
} Linklist;
//链表的初始化
Linklist* Initial_linklist(){
//向系统申请内存
Linklist *head = (Linklist *)malloc(sizeof(Linklist));
head->next = NULL;
return head;
}
//创建初始链表 采用尾插法
void Create_linklist(Linklist *head, int n) { //头节点(不带数据)
Linklist *node, *end; //普通节点 尾节点
end = head; //当链表为空时 头尾指向同一个节点
printf("创建链表输入 %d 个元素:", n);
for (int i = 0; i < n; i++) { //n为插入普通节点的个数
node = (Linklist *)malloc(sizeof(Linklist));
scanf("%d", &node->data);
end->next = node; //当前end的next指向了新节点node
end = node; //end往后移,此时新的节点变成尾节点
}
end->next = NULL; //end最后置NULL
}
//打印链表
void Show_linklist(Linklist *head) {
Linklist *t = head->next; //t为遍历指针 访问每个节点数据
if (t == NULL)
puts("链表为空");
while (t != NULL) {
printf("%d ", t->data);
t = t->next;
}
printf("\n\n");
}
void Delete_same(Linklist *head) {
Linklist *t = head->next; //t遍历指针
while (t != NULL) {
Linklist *p1 = t; //p1指向t的位置
Linklist *p2 = t->next; //p2指向p1之后的位置
//p1和p2永远是相邻的
while (p2 != NULL) {
//删除的永远是p2指向的节点
if (p1->data == p2->data) {
p1->next = p2->next; //p1的next跨过删除的指向之前p2的next
free(p2);
p2 = p1->next; //p2再次指向p1的next
} else {
p1 = p1->next; //两个指针同时往后移
p2 = p2->next;
}
}
t = t->next;
}
}
int main(){
Linklist *mylist;
mylist = Initial_linklist();
Create_linklist(mylist, 10);
printf("初始状态链表:\n");
Show_linklist(mylist);
Delete_same(mylist);
printf("链表进行去重后:\n");
Show_linklist(mylist);
}
程序测试运行结果
一切都是命运石之门的选择,本文章来源于博客园,作者:MarisaMagic,出处:https://www.cnblogs.com/MarisaMagic/p/17018365.html,未经允许严禁转载