【模板小程式】鏈表排序(qsort/insert_sort/merge_sort)

来源:http://www.cnblogs.com/xiaoxi666/archive/2017/08/04/7287065.html
-Advertisement-
Play Games

前言 本文章整理了鏈表排序的三種方法,分別是快速排序、插入排序、歸併排序。為適應不同用途,先給出常用的int版本,再在此基礎上抽象出類模板。 目錄 一、針對整數的版本(常用) 二、模板版本(適用性廣泛) 總結 參考文章 一、針對整數的版本(常用) 文中鏈表定義: 鏈表相關操作: 三種排序方法: 完整 ...


前言

本文章整理了鏈表排序的三種方法,分別是快速排序、插入排序、歸併排序。為適應不同用途,先給出常用的int版本,再在此基礎上抽象出類模板。

目錄

一、針對整數的版本(常用)

  1. 文中鏈表定義
  2. 鏈表相關操作
  3. 三種排序方法
  4. 完整測試程式

二、模板版本(適用性廣泛)

  1. 文中鏈表定義
  2. 鏈表相關操作
  3. 三種排序方法
  4. 完整測試程式

總結

參考文章

一、針對整數的版本(常用)

文中鏈表定義:

1 //definition for singly-linked list.
2 struct ListNode
3 {
4     int val;
5     ListNode* next;
6     ListNode(int x) : val(x), next(NULL) {}
7 };

鏈表相關操作:

 1 //鏈表結點構造
 2 ListNode*  create_list_node(int val)
 3 {
 4     ListNode* pNode = new ListNode(val);
 5     return pNode;
 6 }
 7 //鏈表結點連接
 8 void connect_list_node(ListNode* pCur, ListNode* pNext)
 9 {
10     pCur->next = pNext;
11 }
12 
13 //銷毀單個節點(其實用這個更好,不會出現空懸指針)
14 void destory_Node(ListNode** ppNode)
15 {
16     if(*ppNode != NULL)
17         delete *ppNode;
18     *ppNode = NULL;
19 }
20 
21 //鏈表銷毀(註意,除頭節點外,其他節點均變成了空懸指針,不建議此用法)
22 void destory_list(ListNode** ppHead)
23 {
24     ListNode** cur = ppHead;
25     while(*cur != NULL)
26     {
27         ListNode* tmp = (*cur)->next;//保存下一個節點
28         delete *cur;
29         *cur = NULL;
30         *cur = tmp;
31     }
32 }
33 
34 //鏈表列印
35 void print_list(ListNode* pHead)
36 {
37     ListNode* cur = pHead;
38     while(cur != NULL)
39     {
40         cout<< cur->val <<" ";
41         cur = cur->next;
42     }
43     cout<<endl;
44 }

三種排序方法:

 1 //鏈表快速排序
 2 class List_qsort
 3 {
 4 private:
 5     //交換元素
 6     void list_swap(int& lhs,int& rhs)
 7     {
 8         int tmp = lhs;
 9         lhs = rhs;
10         rhs = tmp;
11     }
12     //劃分,使左邊小於頭結點元素,右邊大於等於頭結點元素
13     ListNode* list_partion(ListNode* pBegin,ListNode* pEnd)
14     {
15         if(pBegin == pEnd || pBegin->next == NULL)
16             return pBegin;
17 
18         ListNode* pSlow=pBegin;
19         ListNode* pFast=pBegin;
20         int key=pBegin->val;
21         while(pFast != pEnd)
22         {
23 
24             if(pFast->val < key)
25             {
26                 pSlow = pSlow->next;
27                 list_swap(pSlow->val,pFast->val);
28             }
29             pFast = pFast->next;
30         }
31 
32         list_swap(pSlow->val,pBegin->val);
33 
34         return pSlow;
35     }
36     //排序輔助函數
37     void _list_qsort(ListNode* pBegin,ListNode* pEnd)
38     {
39         if(pBegin == pEnd || NULL == pBegin->next)
40             return;
41         ListNode* mid=list_partion(pBegin,pEnd);
42         _list_qsort(pBegin,mid);
43         _list_qsort(mid->next,pEnd);
44     }
45 public:    
46     //排序入口函數(版本1:傳值)
47     void list_qsort(ListNode* pHead)
48     {
49         if(pHead == NULL || pHead->next ==NULL)
50             return ;
51         _list_qsort(pHead,NULL);
52 
53     }
54 
55     /*
56     //排序入口函數(版本2:傳指針)
57     void list_qsort(ListNode** ppHead)
58     {
59         if(*ppHead == NULL || (*ppHead)->next ==NULL)
60             return;
61         _list_qsort(*ppHead,NULL);
62     }
63     */
64 
65     /*
66     //排序入口函數(版本3:傳引用)
67     void list_qsort(ListNode*& pHead)
68     {
69         if(NULL == pHead  || NULL == pHead->next )
70             return;
71         _list_qsort(pHead,NULL);
72     }
73     */
74 };
  1 //鏈表插入排序
  2 class List_insertion_sort
  3 {
  4 
  5     //版本1:指針的指針
  6 private:
  7     //對於待插入的節點,選擇合適的位置插入
  8     void _list_insert_sort(ListNode** ppNode, ListNode *pNode)
  9     {
 10         ListNode* prev = NULL;
 11         ListNode* cur = NULL;
 12 
 13         if(pNode->val < (*ppNode)->val)
 14         {
 15             pNode->next = *ppNode;
 16             (*ppNode) = pNode;
 17             return;
 18         }
 19 
 20         cur = *ppNode;
 21 
 22         while(cur != NULL)
 23         {
 24             if(pNode->val < cur->val)
 25                 break;
 26 
 27             prev = cur;
 28             cur = cur->next;
 29         }
 30 
 31         pNode->next = cur;//或pNode->next = prev->next
 32         prev->next =pNode;
 33         return;
 34     }
 35 public:
 36     //首先遍歷節點,一邊是排序好的節點,一邊是待排序的節點
 37     void list_insert_sort(ListNode** ppNode)
 38     {
 39         ListNode* prev = NULL;
 40         ListNode* cur = NULL;
 41 
 42         if(NULL == ppNode || NULL == *ppNode)
 43             return;
 44 
 45         cur = (*ppNode)->next;
 46         (*ppNode)->next = NULL;
 47 
 48         while(cur != NULL)
 49         {
 50             prev = cur;
 51             cur = cur->next;
 52             _list_insert_sort(ppNode,prev);
 53         }
 54     }
 55 
 56     /*
 57     //版本2:指針的引用
 58 private:
 59     //對於待插入的節點,選擇合適的位置插入
 60     void _list_insert_sort(ListNode*& ppNode, ListNode *pNode)
 61     {
 62         ListNode* prev = NULL;
 63         ListNode* cur = NULL;
 64 
 65         if(pNode->val < ppNode->val)
 66         {
 67             pNode->next = ppNode;
 68             ppNode = pNode;
 69             return;
 70         }
 71 
 72         cur = ppNode;
 73 
 74         while(cur != NULL)
 75         {
 76             if(pNode->val < cur->val)
 77                 break;
 78 
 79             prev = cur;
 80             cur = cur->next;
 81         }
 82 
 83         pNode->next = cur;//或pNode->next = prev->next
 84         prev->next =pNode;
 85         return;
 86     }
 87 public:
 88     //首先遍歷節點,一邊是排序好的節點,一邊是待排序的節點
 89     void list_insert_sort(ListNode*& ppNode)
 90     {
 91         ListNode* prev = NULL;
 92         ListNode* cur = NULL;
 93 
 94         if(NULL == ppNode)
 95             return;
 96 
 97         cur = ppNode->next;
 98         ppNode->next = NULL;
 99 
100         while(cur != NULL)
101         {
102             prev = cur;
103             cur = cur->next;
104             _list_insert_sort(ppNode,prev);
105         }
106     }
107 */
108 
109 };
 1 //鏈表歸併排序
 2 class List_merge_sort
 3 {
 4 private:
 5     //合併兩端鏈表
 6     //因為可能在頭結點之前插入數據,故為ListNode** list1
 7     ListNode* list_merge(ListNode* list1, ListNode* list2)
 8     {
 9         if(NULL == list1)
10             return list2;
11         else if(NULL == list2)
12             return list1;
13 
14         ListNode* dummy = new ListNode(-1);//輔助頭結點
15         dummy->next = list1;
16         ListNode* list1_cur = dummy;
17         ListNode* list2_cur = list2;
18 
19         while(list1_cur->next != NULL && list2_cur != NULL)
20         {
21             //cout<< list1_cur->next->val <<"==="<< list2_cur->val<<endl;
22             //把後面一段list2更小的元素插入前面一段list1中
23             if(list1_cur->next->val > list2_cur->val)//註意:不可以是大於等於,那樣就不穩定了
24             {
25                 list2 = list2->next;
26                 list2_cur->next = list1_cur->next;
27                 list1_cur->next = list2_cur;
28                 list1_cur = list2_cur;
29                 list2_cur = list2;
30             }
31             else//後面一段list2的元素大於等於前面一段list1的元素時,前面一段指針直接後移
32                 list1_cur = list1_cur->next;
33         }
34         //後面一段list2中可能還有元素或NULL,總之把它接到list1後面
35         if(NULL == list1_cur->next)
36             list1_cur->next = list2_cur;
37         
38         ListNode* pHead = dummy->next;
39         delete dummy;//釋放dummy
40         return pHead;//返回頭結點
41     }
42 
43     //歸併排序輔助函數(因為可能在頭結點之前插入數據,故為ListNode** pHead)
44     ListNode* _list_merge_sort(ListNode** pHead)
45     {
46         if(NULL == *pHead || NULL == (*pHead)->next)
47             return *pHead;
48 
49         ListNode* pSlow = *pHead;
50         ListNode* pFast = *pHead;
51         while(pFast->next !=NULL && pFast->next->next !=NULL)
52         {
53             pSlow = pSlow->next;
54             pFast = pFast->next->next;
55         }
56 
57         ListNode* pLeftHead = *pHead;
58         ListNode* pRightHead = pSlow->next;
59         pSlow->next = NULL;//左半鏈表尾節點的next賦空值
60 
61         /*pLeftHead = */_list_merge_sort(&pLeftHead);
62         /*pRightHead = */_list_merge_sort(&pRightHead);
63 
64         //註意:雖然傳值,但是內部狀態可變,因此pLeftHead和pRightHead內部
65         //的的next可能已經變了,因此他們可能伸長或縮短
66         *pHead = list_merge(pLeftHead,pRightHead);//修改頭指針
67         return *pHead;
68     }
69 public:
70     //歸併排序入口,去掉了返回值,不包裝這一層也行
71     void list_merge_sort(ListNode** pHead)
72     {
73         _list_merge_sort(pHead);//註意這裡傳入的是地址
74     }
75 };

完整測試程式:

  1 /*
  2 本程式說明:
  3 
  4 鏈表排序各種方法(快速排序)
  5 
  6 參考鏈接:
  7     http://blog.csdn.net/u012658346/article/details/51141288
  8     http://www.jb51.net/article/37300.htm
  9 
 10 */
 11 #include <iostream>
 12 using namespace std;
 13 
 14 
 15 //definition for singly-linked list.
 16 struct ListNode
 17 {
 18     int val;
 19     ListNode* next;
 20     ListNode(int x) : val(x), next(NULL) {}
 21 };
 22 
 23 //鏈表結點構造
 24 ListNode*  create_list_node(int val)
 25 {
 26     ListNode* pNode = new ListNode(val);
 27     return pNode;
 28 }
 29 //鏈表結點連接
 30 void connect_list_node(ListNode* pCur, ListNode* pNext)
 31 {
 32     pCur->next = pNext;
 33 }
 34 
 35 //銷毀單個節點(其實用這個更好,不會出現空懸指針)
 36 void destory_Node(ListNode** ppNode)
 37 {
 38     if(*ppNode != NULL)
 39         delete *ppNode;
 40     *ppNode = NULL;
 41 }
 42 
 43 //鏈表銷毀(註意,除頭節點外,其他節點均變成了空懸指針)
 44 void destory_list(ListNode** ppHead)
 45 {
 46     ListNode** cur = ppHead;
 47     while(*cur != NULL)
 48     {
 49         ListNode* tmp = (*cur)->next;//保存下一個節點
 50         delete *cur;
 51         *cur = NULL;
 52         *cur = tmp;
 53     }
 54 }
 55 
 56 //鏈表列印
 57 void print_list(ListNode* pHead)
 58 {
 59     ListNode* cur = pHead;
 60     while(cur != NULL)
 61     {
 62         cout<< cur->val <<" ";
 63         cur = cur->next;
 64     }
 65     cout<<endl;
 66 }
 67 
 68 //鏈表快速排序
 69 class List_qsort
 70 {
 71 private:
 72     //交換元素
 73     void list_swap(int& lhs,int& rhs)
 74     {
 75         int tmp = lhs;
 76         lhs = rhs;
 77         rhs = tmp;
 78     }
 79     //劃分,使左邊小於頭結點元素,右邊大於等於頭結點元素
 80     ListNode* list_partion(ListNode* pBegin,ListNode* pEnd)
 81     {
 82         if(pBegin == pEnd || pBegin->next == NULL)
 83             return pBegin;
 84 
 85         ListNode* pSlow=pBegin;
 86         ListNode* pFast=pBegin;
 87         int key=pBegin->val;
 88         while(pFast != pEnd)
 89         {
 90 
 91             if(pFast->val < key)
 92             {
 93                 pSlow = pSlow->next;
 94                 list_swap(pSlow->val,pFast->val);
 95             }
 96             pFast = pFast->next;
 97         }
 98 
 99         list_swap(pSlow->val,pBegin->val);
100 
101         return pSlow;
102     }
103     //排序輔助函數
104     void _list_qsort(ListNode* pBegin,ListNode* pEnd)
105     {
106         if(pBegin == pEnd || NULL == pBegin->next)
107             return;
108         ListNode* mid=list_partion(pBegin,pEnd);
109         _list_qsort(pBegin,mid);
110         _list_qsort(mid->next,pEnd);
111     }
112 public:    
113     //排序入口函數(版本1:傳值)
114     void list_qsort(ListNode* pHead)
115     {
116         if(pHead == NULL || pHead->next ==NULL)
117             return ;
118         _list_qsort(pHead,NULL);
119 
120     }
121 
122     /*
123     //排序入口函數(版本2:傳指針)
124     void list_qsort(ListNode** ppHead)
125     {
126         if(*ppHead == NULL || (*ppHead)->next ==NULL)
127             return;
128         _list_qsort(*ppHead,NULL);
129     }
130     */
131 
132     /*
133     //排序入口函數(版本3:傳引用)
134     void list_qsort(ListNode*& pHead)
135     {
136         if(NULL == pHead  || NULL == pHead->next )
137             return;
138         _list_qsort(pHead,NULL);
139     }
140     */
141 };
142 
143 //鏈表插入排序
144 class List_insertion_sort
145 {
146 
147     //版本1:指針的指針
148 private:
149     //對於待插入的節點,選擇合適的位置插入
150     void _list_insert_sort(ListNode** ppNode, ListNode *pNode)
151     {
152         ListNode* prev = NULL;
153         ListNode* cur = NULL;
154 
155         if(pNode->val < (*ppNode)->val)
156         {
157             pNode->next = *ppNode;
158             (*ppNode) = pNode;
159             return;
160         }
161 
162         cur = *ppNode;
163 
164         while(cur != NULL)
165         {
166             if(pNode->val < cur->val)
167                 break;
168 
169             prev = cur;
170             cur = cur->next;
171         }
172 
173         pNode->next = cur;//或pNode->next = prev->next
174         prev->next =pNode;
175         return;
176     }
177 public:
178     //首先遍歷節點,一邊是排序好的節點,一邊是待排序的節點
179     void list_insert_sort(ListNode** ppNode)
180     {
181         ListNode* prev = NULL;
182         ListNode* cur = NULL;
183 
184         if(NULL == ppNode || NULL == *ppNode)
185             return;
186 
187         cur = (*ppNode)->next;
188         (*ppNode)->next = NULL;
189 
190         while(cur != NULL)
191         {
192             prev = cur;
193             cur = cur->next;
194             _list_insert_sort(ppNode,prev);
195         }
196     }
197 
198     /*
199     //版本2:指針的引用
200 private:
201     //對於待插入的節點,選擇合適的位置插入
202     void _list_insert_sort(ListNode*& ppNode, ListNode *pNode)
203     {
204         ListNode* prev = NULL;
205         ListNode* cur = NULL;
206 
207         if(pNode->val < ppNode->val)
208         {
209             pNode->next = ppNode;
210             ppNode = pNode;
211             return;
212         }
213 
214         cur = ppNode;
215 
216         while(cur != NULL)
217         {
218             if(pNode->val < cur->val)
219                 break;
220 
221             prev = cur;
222             cur = cur->next;
223         }
224 
225         pNode->next = cur;//或pNode->next = prev->next
226         prev->next =pNode;
227         return;
228     }
229 public:
230     //首先遍歷節點,一邊是排序好的節點,一邊是待排序的節點
231     void list_insert_sort(ListNode*& ppNode)
232     {
233         ListNode* prev = NULL;
234         ListNode* cur = NULL;
235 
236         if(NULL == ppNode)
237             return;
238 
239         cur = ppNode->next;
240         ppNode->next = NULL;
241 
242         while(cur != NULL)
243         {
244             prev = cur;
245             cur = cur->next;
246             _list_insert_sort(ppNode,prev);
247         }
248     }
249 */
250 
251 };
252 
253 
254 //鏈表歸併排序
255 class List_merge_sort
256 {
257 private:
258     //合併兩端鏈表
259     //因為可能在頭結點之前插入數據,故為ListNode** list1
260     ListNode* list_merge(ListNode* list1, ListNode* list2)
261     {
262         if(NULL == list1)
263             return list2;
264         else if(NULL == list2)
265             return list1;
266 
267         ListNode* dummy = new ListNode(-1);//輔助頭結點
268         dummy->next = list1;
269         ListNode* list1_cur = dummy;
270 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • from flask import Flask,make_response,jsonify,request,url_for,g from flask_restful import reqparse, abort, Api, Resource from flask_httpauth import HT... ...
  • Java 記憶體區域和GC機制 目錄 Java垃圾回收概況 Java記憶體區域 Java對象的訪問方式 Java記憶體分配機制 Java GC機制 垃圾收集器 Java垃圾回收概況 Java GC(Garbage Collection,垃圾收集,垃圾回收)機制,是Java與C++/C的主要區別之一,作為J ...
  • 總結:本篇博客介紹使用gregwar/captcha實現驗證碼的具體操作步驟,以及可能遇到的問題和解決辦法。 操作步驟: 1, 在laravel5.4項目根目錄下找到 composer.json 這個文件, 添加 "gregwar/captcha": "1.*" 到composer.json這個文件 ...
  • 簡單的寫了一個爬取www.seebug.org上poc的小玩意兒~ 首先我們進行一定的抓包分析 我們遇到的第一個問題就是seebug需要登錄才能進行下載,這個很好處理,只需要抓取返回值200的頁面,將我們的headers信息複製下來就行了 (這裡我就不放上我的headers信息了,不過headers ...
  • Lua語言是一門非常小巧精悍的腳本語言,是C/C++天然的好伴侶。這門語言非常的簡單,但是卻有很多語法細節與C語系不同。熟悉C語系語言的同學們剛接觸這門語言的話,可能會因為數組下標從1開始等原因而感到憤怒。這些細節在剛上手的時候全部記下來確實有些困難。湊巧,我也經歷了這麼一個過程。所以在這裡我就把我... ...
  • 閱讀目錄 Checkbutton Radiobutton LabelFrame checkbutton : 說明:多選框控制項,用於在程式中提供多項選擇框,但是處理“多選一”的問題,還是交給 Radiobutton 或 Listbox 組件來實現吧。 用法:使用 Checkbutton,你必須創建一個 ...
  • 作者:溫學良 鏈接:https://www.zhihu.com/question/21416727/answer/82511153 來源:知乎 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。 Web伺服器習慣處理靜態頁面,所以需要一個程式來幫忙處理動態請求(如當前時間)。Web ...
  • 學了數組之後,感覺有好多操作需要經常去寫,很不方便,因此自己做了一個工具類,方便調用,方法可能不全,希望大家可以添加,讓我使用也方便一點兒。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...