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