文章目录
- 前言
- 一、关于链表的创建
- 二、单链表的应用
- 1.删除排序链表中的重复元素
- 2.找到中间结点
- 3.反转链表
- 4.合并两个有序链表
- 主函数(包含以上所有函数)
- 5.回文链表(不带头节点)
前言
链表的基本操作思路都不难,但是函数很多,在学习的过程中也不能只敲函数,还要多联系完整版的链表,要有输出,今天就教大家写完整版的代码啦。还有我在学习链表的时候遇到的困难,也帮大家避雷啦。
一、关于链表的创建
#include二、单链表的应用 1.删除排序链表中的重复元素#include typedef struct Node{ int data; struct Node*next; }Node,*Linklist; //Node 表示一个Node类型的指针,*Linklist则代表传入的一整个链表; //初始化单链表(建立链表必须要做的事) Linklist Insertlist() { Linklist head; head = (Node*)malloc(sizeof(Node)); head->next = NULL; return head; } //接下来用尾插法建立一个单链表, //也可以用头插,但是头插法建立的单链表是倒序的 void creatlist(Linklist head) { Node* r, * s; r = head; int data; while (1) { scanf_s("%d", &data); if (data == 0) { break; } s = (Node*)malloc(sizeof(Node)); s->data = data; r->next = s; r = s; r->next = NULL; } }
思路:由于给定的链表的排好序的,所以重复的元素在链表中的位置是连续的,因此我们只需要对链表进行一次遍历,找到相同的元素让他指向下一个就行。
代码如下(示例):
//删除两个相同的元素
Linklist deletesome(Linklist head)
{
if (head == NULL || head->next == NULL)
return head;
Node* p = head;
while (p) {
if (p->data == p->next->data) {
p->next = p->next->next;
}
else {
p = p->next;
}
}
return head;
}
2.找到中间结点
代码如下(示例):
//找到中间节点
void middlenode(Linklist head)
{
Node* fast = head->next;
Node* slow = head->next;
while (fast != NULL && fast->next != NULL) {
fast = fast->next->next;
slow = slow->next;
}
printd("%d ",slow->data);
}
3.反转链表
思路:对于反转链表,其实有很多方法,比如直接用头插法创建链表再打印出来就可以反转,也可以改变指针的指向(后面写回文联表会用到,一般用于不带头结点的链表),这里我们介绍一种比较好理解的递归(用于带有节点的链表)。
代码如下(示例):
void daoxv(Linklist head)
{
if (head->next != NULL) {
daoxv(head->next);
}
printf("%d ", head->data);
}
4.合并两个有序链表
题目:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
思路:通过遍历链表比较连个链表的大小,重新定义指针的排序,可以直接比较,也可以用递归简化代码;
代码如下(示例):
//递归
Linklist mergeTwoLists(Linklist list1,Linklist list2)
{
if (list1 == NULL) {
return list2;
}
if (list2 == NULL) {
return list1;
}
if (list1->data >= list2->data) {
list2->next = mergeTwoLists(list1, list2->next);
return list2;
}
else {
list1->next =mergeTwoLists(list1->next, list2);
return list1;
}
}
主函数(包含以上所有函数)
int main()
{
Linklist head;
Linklist list1,list2,list3;
Linklist head;
head = Insertlist();
list1 = Insertlist();
list2 = Insertlist();
list3 = Insertlist();
creatlist(list1);
creatlist(list2);
creatlist(list3);
creatlist(head);
middlenode(head);
deletesome(head);
daoxv(head->next);
mergeTwoLists(list1,list2,list3);
print(head);
}
5.回文链表(不带头节点)
题目:给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
思路:回文链表可以用数组,递归和快慢指针的方式,在这里我们采用快慢指针来做,加深对不带头节点的链表反转的理解。
整个流程可以分为以下五个步骤:
找到前半部分链表的尾节点。
反转后半部分链表。
判断是否回文。
恢复链表。
返回结果。
代码如下(示例):
#include#include typedef struct Node { int data; struct Node* next; }Node, * Linklist; void Insertlist(Linklist* L) { *L = NULL; } Linklist creatlist(Linklist* L) { Node* s, * r; int data; scanf_s("%d", &data); if (data != -1) { *L = (Linklist)malloc(sizeof(Node)); (*L)->next = NULL; (*L)->data = data; r = *L; scanf_s("%d", &data); while (data != -1) { s = (Node*)malloc(sizeof(Node)); s->data = data; s->next = NULL; r->next = s; r = r->next; scanf_s("%d", &data); } } return *L; } bool huiwen(Linklist L) { if (L == NULL || L->next == NULL) return true; if (L->next->next == NULL) { if (L->data == L->next->data) return true; else return false; } Node* fast, * slow; fast = L->next->next; slow = L->next; while (fast && fast->next != NULL) { fast = fast->next->next; slow = slow->next; } Node* p, * q; p = q = NULL; while (L != slow) { q = L->next; L->next = p; p = L; L = q; } if (fast != NULL && fast->next == NULL) { slow = slow->next; } while (p != NULL) { if (p->data != slow->data) return false; p = p->next; slow = slow->next; } return true; } int main() { Linklist L; Insertlist(&L); creatlist(&L); if (huiwen(L)) { printf("truen"); } else { printf("falsen"); } }



