[数据结构]有序单向链表的去重(C语言)

单向链表的去重

问题描述及分析

给定一个有序的链表,去除重复出现的元素,使每个元素只出现一次。例如一个单向链表为 1->1->2->2->3->4->4->∅ , 那么去重后得到的单向链表为 1->2->3->4->∅ 。

这里的链表保证是有序的,所以出现的重复元素都是相邻的,所以对整个链表进行一次遍历,在遍历的过程中删除这些相邻的重复元素即可。
首先,需要一个遍历指针 t 指向当前遍历到的节点,然后定义两个指针分别为 p1p2p1 指向 t 所指向的节点,而 p2 指向此时 p1 的下一个节点,如果 p2 指向节点的值与 p1 的相同,那么直接让 p1next 跳过 p2 指向 p2next 即可。有可能存在相邻很多个元素都相等,所以可以加一个循环,一次性删除多个和 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);
}

程序测试运行结果

posted @ 2023-01-01 17:54  MarisaMagic  阅读(308)  评论(0编辑  收藏  举报