【数据结构】链表-C语言版(二)

简介: 【数据结构】链表-C语言版

链表应用OJ题

1.删除链表中等于给定值val的所有节点,OJ链接

分析:

(1)要删除某一结点,需要保存该结点的前一个结点(删除当前节点后,前一结点应指向当前结点的下一结点),同时需要保存当前结点的下一结点(删除当前结点后,能够继续向后访问该链表)

(2)操作:

       遍历链表,如果当前结点值==val,就保存当前结点的下一个结点,前一结点指向当前结点的下一结点,释放当前结点,当前结点指向下一结点;

       如果当前结点值!=val,前一结点挪到当前结点位置,当前结点挪到下一结点位置。需要考虑特殊情况,第一个结点值 == val时,此时prev=NULL需要特殊处理。

不带哨兵位头结点解法:

1. /**
2.  * Definition for singly-linked list.
3.  * struct ListNode {
4.  *     int val;
5.  *     struct ListNode *next;
6.  * };
7.  */
8. 
9. struct ListNode* removeElements(struct ListNode* head, int val){
10. 
11.     struct ListNode* prev = NULL;
12.     struct ListNode* cur = head;
13. 
14.     while(cur)
15.     {
16.         if(cur->val == val)//找到了
17.         {
18.             struct ListNode* next = cur->next;//要free(cur),就必须要先保存cur的下一个结点,否则无法继续访问下一结点
19.             if(prev == NULL)//cur是头,要删除的结点在第一个位置
20.             {
21.                 free(cur);
22.                 head = next;
23.                 cur = next;
24.             }
25.             else
26.             {
27.                 prev->next = next;
28.                 free(cur);
29.                 cur = next;
30.             }   
31.         }
32.         else
33.         {
34.             prev = cur;
35.             cur = cur->next;    
36.         }
37.       
38.     }   
39.     return head;
40. }

带哨兵位头结点解法:

1. /**
2.  * Definition for singly-linked list.
3.  * struct ListNode {
4.  *     int val;
5.  *     struct ListNode *next;
6.  * };
7.  */
8. 
9. struct ListNode* removeElements(struct ListNode* head, int val)
10. {
11.     struct ListNode* guardHead = (struct ListNode*)malloc(sizeof(struct ListNode));
12.     guardHead->next = head;
13. 
14.     struct ListNode* prev = guardHead;
15.     struct ListNode* cur = head;
16. 
17.     while (cur)
18.     {
19.         if (cur->val == val)
20.         {
21.             struct ListNode* next = cur->next;
22.             prev->next = next;
23.             free(cur);
24.             cur = next;
25.         }
26.         else
27.         {
28.             prev = cur;
29.             cur = cur->next;
30.         }
31.     }
32. 
33.     head = guardHead->next;
34.     free(guardHead);
35.     guardHead = NULL;
36.     return head;
37. 
38. }

2.反转一个单链表 OJ链接

分析:

解法一:如果只定义两个节点,当n2指向n1时,n2的下一个结点就找不到了。因此要定义3个节点,n1和n2用于翻转,n3用于迭代:n1指向NULL,n2指向n1,n3用于记录n2的下一个结点。

1. /**
2.  * Definition for singly-linked list.
3.  * struct ListNode {
4.  *     int val;
5.  *     struct ListNode *next;
6.  * };
7.  */
8. 
9. struct ListNode* reverseList(struct ListNode* head)
10. {
11.     if(head == NULL || head->next == NULL)
12.     {
13.         return head;
14.     }
15.     
16.     struct ListNode* n1 = NULL,*n2 = head,*n3 = head->next;
17.     while(n2)
18.     {
19.         n2->next = n1;
20.         n1 = n2;
21.         n2 = n3;
22.         if(n3)
23.         {
24.             n3 = n3->next;
25.         }
26.     }
27.     return n1;
28. }

解法二:头插法,依次取原链表中的节点头插到新节点

1. /**
2.  * Definition for singly-linked list.
3.  * struct ListNode {
4.  *     int val;
5.  *     struct ListNode *next;
6.  * };
7.  */
8. 
9. struct ListNode* reverseList(struct ListNode* head)
10. {
11.     struct ListNode* cur = head;
12.     struct ListNode* newHead = NULL;
13. 
14.     while(cur)
15.     {
16.         struct ListNode* next = cur->next;
17. 
18.         cur->next = newHead;
19.         newHead = cur;
20.         cur = next;
21.     }
22.     return newHead;
23. }

3.链表的中间结点   OJ链接

分析:只能遍历一遍,可以用快慢指针,慢指针每次走一步,快指针每次走两步

1. /**
2.  * Definition for singly-linked list.
3.  * struct ListNode {
4.  *     int val;
5.  *     struct ListNode *next;
6.  * };
7.  */
8. 
9. 
10. struct ListNode* middleNode(struct ListNode* head)
11. {
12.     struct ListNode* slow = head;
13.     struct ListNode* fast = head;
14. 
15.     while(fast && fast->next)
16.     {
17.         slow = slow->next;
18.         fast = fast->next->next;
19.     }
20. 
21.     return slow;
22. }

4.输出链表倒数第k个结点,OJ链接

分析:如何找倒数第k个结点,可以使用快慢指针 ,让快指针先走k步,再让慢指针开始走,此时快慢指针相差k步,然后快慢指针一起向后移动,等快指针移动到链表末尾NULL时,慢指针的位置就是倒数第k个结点位置。

1. struct ListNode 
2. {
3.  int val;
4.  struct ListNode *next;
5. };
6. 
7. struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) 
8. {
9.     
10.     if(pListHead == NULL)
11.     {
12.         return NULL;
13.     }
14. 
15.     struct ListNode* slow = pListHead;
16.     struct ListNode* fast = pListHead;
17.     
18.     while(k--)
19.     {
20.         if(fast == NULL)
21.         {
22.             return NULL;
23.         }
24.         fast = fast->next;
25.     }
26.     
27.     while(fast)
28.     {
29.         slow = slow->next;
30.         fast = fast->next;
31.     }
32.     
33.     return slow;
34. }

5.合并两个有序链表 OJ链接

分析:尾插法,找第一个结点小的链表当作新表头,找尾比较麻烦,需要遍历,因此直接定义一个尾节点tail,每次让tail指向刚插入的节点,当有一个链表走完时就停下,再把没走完的链表全部连接到tail上。

1. struct ListNode {
2.     int val;
3.     struct ListNode *next;
4. };
5. 
6. struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2)
7. {
8. 
9.     struct ListNode* head,*tail =  NULL;
10.     if(l1 == NULL)
11.     {
12.         return l2;
13.     }
14.     if(l2 == NULL)
15.     {
16.         return l1;
17.     }
18. 
19.     if(l1->val < l2->val)
20.     {
21.         head = tail = l1;
22.         l1 = l1->next; 
23.     }
24.     else
25.     {
26.         head = tail = l2;
27.         l2 = l2->next; 
28.     }
29. 
30.     while(l1 && l2)
31.     {
32.         if(l1->val < l2->val)
33.         {
34.             tail->next = l1; 
35.             l1 = l1->next;
36.             tail = tail->next; 
37.         }
38.         else
39.         {
40.             tail->next = l2;
41.             l2 = l2->next;
42.             tail = tail->next;
43.         }
44.     }
45. 
46.     if(l1 == NULL)
47.     {
48.         tail->next = l2;
49.     }
50.     else
51.     {
52.         tail->next = l1;
53.     }
54. 
55.     return head;
56. 
57. }

6.编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 OJ链接

分析:申请两个链表,一个放比x小的节点,一个放比x大的节点,最后将大链表链接在小链表末尾即可。

1. 
2. struct ListNode {
3.     int val;
4.     struct ListNode *next;
5.     ListNode(int x) : val(x), next(NULL) {}
6. };
7. 
8. class Partition {
9. public:
10.     ListNode* partition(ListNode* pHead, int x) {
11.         // 有头指针
12.         struct ListNode* lessHead,* lessTail,*greaterHead,*greaterTail;
13.         lessHead = lessTail = (struct ListNode*)malloc(sizeof(struct ListNode));
14.         greaterHead = greaterTail = (struct ListNode*)malloc(sizeof(struct ListNode));
15.       
16.         lessTail->next = NULL;
17.         greaterTail->next = NULL;
18.       
19.         struct ListNode *cur = pHead;
20.       
21.         while(cur)
22.         {
23.             if(cur->val<x)
24.             {
25.                 lessTail->next = cur;
26.                 lessTail = lessTail->next;
27.             }
28.             else
29.             {
30.                 greaterTail->next = cur;
31.                 greaterTail = greaterTail->next;
32.             }
33.             cur = cur->next;
34.         }
35.       
36.         lessTail->next = greaterHead->next;
37.         greaterTail->next = NULL;
38.       
39.         pHead = lessHead->next;
40.         free(lessHead);
41.         free(greaterHead);
42.       
43.         return pHead;
44.     }
45. };


相关文章
|
2月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
70 1
|
2月前
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
71 4
|
2月前
|
存储 机器学习/深度学习 搜索推荐
【趣学C语言和数据结构100例】86-90
本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。
56 4
|
2月前
|
存储 算法 数据处理
【趣学C语言和数据结构100例】81-85
本文介绍了五个经典算法问题及其C语言实现,涵盖图论与树结构的基础知识。包括使用BFS求解单源最短路径、统计有向图中入度或出度为0的点数、统计无向无权图各顶点的度、折半查找及二叉排序树的查找。这些算法不仅理论意义重大,且在实际应用中极为广泛,有助于提升编程能力和数据结构理解。
58 4
|
2月前
|
算法 数据可视化 数据建模
【趣学C语言和数据结构100例】76-80
本文介绍了五种图论算法的C语言实现,涵盖二叉树的层次遍历及广度优先搜索(BFS)和深度优先搜索(DFS)的邻接表与邻接矩阵实现。层次遍历使用队列按层访问二叉树节点;BFS利用队列从源节点逐层遍历图节点,适用于最短路径等问题;DFS通过递归或栈深入图的分支,适合拓扑排序等场景。这些算法是数据结构和算法学习的基础,对提升编程能力和解决实际问题至关重要。
62 4
|
2月前
|
存储 算法 vr&ar
【趣学C语言和数据结构100例】71-75
本文介绍了五个C语言数据结构问题及其实现,涵盖链表与二叉树操作,包括按奇偶分解链表、交换二叉树左右子树、查找节点的双亲节点、计算二叉树深度及求最大关键值。通过递归和遍历等方法,解决了理论与实际应用中的常见问题,有助于提升编程能力和数据结构理解。
52 4
|
2月前
|
存储 算法 C语言
【趣学C语言和数据结构100例】66-70
本书《趣学C语言和数据结构100例》精选了5个典型的数据结构问题及C语言实现,涵盖链表与数组操作,如有序集合的集合运算、有序序列表的合并、数组中两顺序表位置互换、三递增序列公共元素查找及奇偶数重排。通过详细解析与代码示例,帮助读者深入理解数据结构与算法设计的核心思想,提升编程技能。
41 4
|
2月前
|
存储 算法 C语言
【趣学C语言和数据结构100例】51-55
本文介绍了五个关于链表操作的C语言实现案例,包括删除单链表中的重复元素、从两个有序链表中查找公共元素、判断一个链表是否为另一链表的连续子序列、判断循环双链表是否对称及合并两个循环单链表。每个案例都详细解析了算法思路与实现方法,涵盖了链表操作的多种场景,旨在帮助读者深入理解链表数据结构的应用,提升算法设计与编程能力。
52 4
|
16天前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
31 5
|
30天前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充