【模板小程序】链表排序(qsort/insert_sort/merge_sort)
2017-08-04 20:47
489 查看
前言
本文章整理了链表排序的三种方法,分别是快速排序、插入排序、归并排序。为适应不同用途,先给出常用的int版本,再在此基础上抽象出类模板。目录
一、针对整数的版本(常用)
文中链表定义
链表相关操作
三种排序方法
完整测试程序
二、模板版本(适用性广泛)
文中链表定义
链表相关操作
三种排序方法
完整测试程序
总结
参考文章
一、针对整数的版本(常用)
文中链表定义:
//definition for singly-linked list. struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(NULL) {} };
链表相关操作:
//链表结点构造 ListNode* create_list_node(int val) { ListNode* pNode = new ListNode(val); return pNode; } //链表结点连接 void connect_list_node(ListNode* pCur, ListNode* pNext) { pCur->next = pNext; } //销毁单个节点(其实用这个更好,不会出现空悬指针) void destory_Node(ListNode** ppNode) { if(*ppNode != NULL) delete *ppNode; *ppNode = NULL; } //链表销毁(注意,除头节点外,其他节点均变成了空悬指针,不建议此用法) void destory_list(ListNode** ppHead) { ListNode** cur = ppHead; while(*cur != NULL) { ListNode* tmp = (*cur)->next;//保存下一个节点 delete *cur; *cur = NULL; *cur = tmp; } } //链表打印(不支持有环的链表;如果链表有环,需判断环入口等等另外处理) void print_list(ListNode* pHead) { ListNode* cur = pHead; while(cur != NULL) { cout<< cur->val <<" "; cur = cur->next; } cout<<endl; }
三种排序方法:
//链表快速排序 class List_qsort { private: //交换元素 void list_swap(int& lhs,int& rhs) { int tmp = lhs; lhs = rhs; rhs = tmp; } //划分,使左边小于头结点元素,右边大于等于头结点元素 ListNode* list_partion(ListNode* pBegin,ListNode* pEnd) { if(pBegin == pEnd || pBegin->next == NULL) return pBegin; ListNode* pSlow=pBegin; ListNode* pFast=pBegin; int key=pBegin->val; while(pFast != pEnd) { if(pFast->val < key) { pSlow = pSlow->next; list_swap(pSlow->val,pFast->val); } pFast = pFast->next; } list_swap(pSlow->val,pBegin->val); return pSlow; } //排序辅助函数 void _list_qsort(ListNode* pBegin,ListNode* pEnd) { if(pBegin == pEnd || NULL == pBegin->next) return; ListNode* mid=list_partion(pBegin,pEnd); _list_qsort(pBegin,mid); _list_qsort(mid->next,pEnd); } public: //排序入口函数(版本1:传值) void list_qsort(ListNode* pHead) { if(pHead == NULL || pHead->next ==NULL) return ; _list_qsort(pHead,NULL); } /* //排序入口函数(版本2:传指针) void list_qsort(ListNode** ppHead) { if(*ppHead == NULL || (*ppHead)->next ==NULL) return; _list_qsort(*ppHead,NULL); } */ /* //排序入口函数(版本3:传引用) void list_qsort(ListNode*& pHead) { if(NULL == pHead || NULL == pHead->next ) return; _list_qsort(pHead,NULL); } */ };
//链表插入排序 class List_insertion_sort { //版本1:指针的指针 private: //对于待插入的节点,选择合适的位置插入 void _list_insert_sort(ListNode** ppNode, ListNode *pNode) { ListNode* prev = NULL; ListNode* cur = NULL; if(pNode->val < (*ppNode)->val) { pNode->next = *ppNode; (*ppNode) = pNode; return; } cur = *ppNode; while(cur != NULL) { if(pNode->val < cur->val) break; prev = cur; cur = cur->next; } pNode->next = cur;//或pNode->next = prev->next prev->next =pNode; return; } public: //首先遍历节点,一边是排序好的节点,一边是待排序的节点 void list_insert_sort(ListNode** ppNode) { ListNode* prev = NULL; ListNode* cur = NULL; if(NULL == ppNode || NULL == *ppNode) return; cur = (*ppNode)->next; (*ppNode)->next = NULL; while(cur != NULL) { prev = cur; cur = cur->next; _list_insert_sort(ppNode,prev); } } /* //版本2:指针的引用 private: //对于待插入的节点,选择合适的位置插入 void _list_insert_sort(ListNode*& ppNode, ListNode *pNode) { ListNode* prev = NULL; ListNode* cur = NULL; if(pNode->val < ppNode->val) { pNode->next = ppNode; ppNode = pNode; return; } cur = ppNode; while(cur != NULL) { if(pNode->val < cur->val) break; prev = cur; cur = cur->next; } pNode->next = cur;//或pNode->next = prev->next prev->next =pNode; return; } public: //首先遍历节点,一边是排序好的节点,一边是待排序的节点 void list_insert_sort(ListNode*& ppNode) { ListNode* prev = NULL; ListNode* cur = NULL; if(NULL == ppNode) return; cur = ppNode->next; ppNode->next = NULL; while(cur != NULL) { prev = cur; cur = cur->next; _list_insert_sort(ppNode,prev); } } */ };
//链表归并排序 class List_merge_sort { private: //合并两端链表 //因为可能在头结点之前插入数据,故为ListNode** list1 ListNode* list_merge(ListNode* list1, ListNode* list2) { if(NULL == list1) return list2; else if(NULL == list2) return list1; ListNode* dummy = new ListNode(-1);//辅助头结点 dummy->next = list1; ListNode* list1_cur = dummy; ListNode* list2_cur = list2; while(list1_cur->next != NULL && list2_cur != NULL) { //cout<< list1_cur->next->val <<"==="<< list2_cur->val<<endl; //把后面一段list2更小的元素插入前面一段list1中 if(list1_cur->next->val > list2_cur->val)//注意:不可以是大于等于,那样就不稳定了 { list2 = list2->next; list2_cur->next = list1_cur->next; list1_cur->next = list2_cur; list1_cur = list2_cur; list2_cur = list2; } else//后面一段list2的元素大于等于前面一段list1的元素时,前面一段指针直接后移 list1_cur = list1_cur->next; } //后面一段list2中可能还有元素或NULL,总之把它接到list1后面 if(NULL == list1_cur->next) list1_cur->next = list2_cur; ListNode* pHead = dummy->next; delete dummy;//释放dummy return pHead;//返回头结点 } //归并排序辅助函数(因为可能在头结点之前插入数据,故为ListNode** pHead) ListNode* _list_merge_sort(ListNode** pHead) { if(NULL == *pHead || NULL == (*pHead)->next) return *pHead; ListNode* pSlow = *pHead; ListNode* pFast = *pHead; while(pFast->next !=NULL && pFast->next->next !=NULL) { pSlow = pSlow->next; pFast = pFast->next->next; } ListNode* pLeftHead = *pHead; ListNode* pRightHead = pSlow->next; pSlow->next = NULL;//左半链表尾节点的next赋空值 /*pLeftHead = */_list_merge_sort(&pLeftHead); /*pRightHead = */_list_merge_sort(&pRightHead); //注意:虽然传值,但是内部状态可变,因此pLeftHead和pRightHead内部 //的的next可能已经变了,因此他们可能伸长或缩短 *pHead = list_merge(pLeftHead,pRightHead);//修改头指针 return *pHead; } public: //归并排序入口,去掉了返回值,不包装这一层也行 void list_merge_sort(ListNode** pHead) { _list_merge_sort(pHead);//注意这里传入的是地址 } };
完整测试程序:
/* 本程序说明: 链表排序各种方法(快速排序) 参考链接: http://blog.csdn.net/u012658346/article/details/51141288 http://www.jb51.net/article/37300.htm */ #include <iostream> using namespace std; //definition for singly-linked list. template <typename T> struct ListNode { T val; ListNode<T>* next; ListNode(T x) : val(x), next(NULL) {} }; //链表结点构造 template <typename T> ListNode<T>* create_list_node(T val) { ListNode<T>* pNode = new ListNode<T>(val); return pNode; } //链表结点连接 template <typename T> void connect_list_node(ListNode<T>* pCur, ListNode<T>* pNext) { pCur->next = pNext; } //销毁单个节点(其实用这个更好,不会出现空悬指针) template <typename T> void destory_Node(ListNode<T>** ppNode) { if(*ppNode != NULL) delete *ppNode; *ppNode = NULL; } //链表销毁(注意,除头节点外,其他节点均变成了空悬指针) template <typename T> void destory_list(ListNode<T>** ppHead) { ListNode<T>** cur = ppHead; while(*cur != NULL) { ListNode<T>* tmp = (*cur)->next;//保存下一个节点 delete *cur; *cur = NULL; *cur = tmp; } } //链表打印 template <typename T> void print_list(ListNode<T>* pHead) { ListNode<T>* cur = pHead; while(cur != NULL) { cout<< cur->val <<" "; cur = cur->next; } cout<<endl; } //链表快速排序 template <typename T> class List_qsort { private: //划分,使左边小于头结点元素,右边大于等于头结点元素 ListNode<T>* list_partion(ListNode<T>* pBegin,ListNode<T>* pEnd) { if(pBegin == pEnd || pBegin->next == NULL) return pBegin; ListNode<T>* pSlow=pBegin; ListNode<T>* pFast=pBegin; ListNode<T>* pKey=new ListNode<T>(pBegin->val);//只为了保存用于比较的val while(pFast != pEnd) { if(pFast->val < pKey->val) { pSlow = pSlow->next; swap(pSlow->val,pFast->val); } pFast = pFast->next; } swap(pSlow->val,pBegin->val); delete pKey;//释放pKey return pSlow; } //排序辅助函数 void _list_qsort(ListNode<T>* pBegin,ListNode<T>* pEnd) { if(pBegin == pEnd || NULL == pBegin->next) return; ListNode<T>* mid=list_partion(pBegin,pEnd); _list_qsort(pBegin,mid); _list_qsort(mid->next,pEnd); } public: //排序入口函数(版本1:传值) void list_qsort(ListNode<T>* pHead) { if(pHead == NULL || pHead->next ==NULL) return ; _list_qsort(pHead,NULL); } /* //排序入口函数(版本2:传指针) void list_qsort(ListNode<T>** ppHead) { if(*ppHead == NULL || (*ppHead)->next ==NULL) return; _list_qsort(*ppHead,NULL); } */ /* //排序入口函数(版本3:传引用) void list_qsort(ListNode<T>*& pHead) { if(NULL == pHead || NULL == pHead->next ) return; _list_qsort(pHead,NULL); } */ }; //链表插入排序 template <typename T> class List_insertion_sort { //版本1:指针的指针 private: //对于待插入的节点,选择合适的位置插入 void _list_insert_sort(ListNode<T>** ppNode, ListNode<T>* pNode) { ListNode<T>* prev = NULL; ListNode<T>* cur = NULL; if(pNode->val < (*ppNode)->val) { pNode->next = *ppNode; (*ppNode) = pNode; return; } cur = *ppNode; while(cur != NULL) { if(pNode->val < cur->val) break; prev = cur; cur = cur->next; } pNode->next = cur;//或pNode->next = prev->next prev->next =pNode; return; } public: //首先遍历节点,一边是排序好的节点,一边是待排序的节点 void list_insert_sort(ListNode<T>** ppNode) { ListNode<T>* prev = NULL; ListNode<T>* cur = NULL; if(NULL == ppNode || NULL == *ppNode) return; cur = (*ppNode)->next; (*ppNode)->next = NULL; while(cur != NULL) { prev = cur; cur = cur->next; _list_insert_sort(ppNode,prev); } } /* //版本2:指针的引用 private: //对于待插入的节点,选择合适的位置插入 void _list_insert_sort(ListNode<T>*& ppNode, ListNode<T> *pNode) { ListNode<T>* prev = NULL; ListNode<T>* cur = NULL; if(pNode->val < ppNode->val) { pNode->next = ppNode; ppNode = pNode; return; } cur = ppNode; while(cur != NULL) { if(pNode->val < cur->val) break; prev = cur; cur = cur->next; } pNode->next = cur;//或pNode->next = prev->next prev->next =pNode; return; } public: //首先遍历节点,一边是排序好的节点,一边是待排序的节点 void list_insert_sort(ListNode<T>*& ppNode) { ListNode<T>* prev = NULL; ListNode<T>* cur = NULL; if(NULL == ppNode) return; cur = ppNode->next; ppNode->next = NULL; while(cur != NULL) { prev = cur; cur = cur->next; _list_insert_sort(ppNode,prev); } } */ }; //链表归并排序 template <typename T> class List_merge_sort { private: //合并两端链表 //因为可能在头结点之前插入数据,故为ListNode<T>** list1 ListNode<T>* list_merge(ListNode<T>* list1, ListNode<T>* list2) { if(NULL == list1) return list2; else if(NULL == list2) return list1; ListNode<T>* dummy = new ListNode<T>(-1);//辅助头结点 dummy->next = list1; ListNode<T>* list1_cur = dummy; ListNode<T>* list2_cur = list2; while(list1_cur->next != NULL && list2_cur != NULL) { //cout<< list1_cur->next->val <<"==="<< list2_cur->val<<endl; //把后面一段list2更小的元素插入前面一段list1中 if(list1_cur->next->val > list2_cur->val)//注意:不可以是大于等于,那样就不稳定了 { list2 = list2->next; list2_cur->next = list1_cur->next; list1_cur->next = list2_cur; list1_cur = list2_cur; list2_cur = list2; } else//后面一段list2的元素大于等于前面一段list1的元素时,前面一段指针直接后移 list1_cur = list1_cur->next; } //后面一段list2中可能还有元素或NULL,总之把它接到list1后面 if(NULL == list1_cur->next) list1_cur->next = list2_cur; ListNode<T>* pHead = dummy->next; delete dummy;//释放dummy return pHead;//返回头结点 } //归并排序辅助函数(因为可能在头结点之前插入数据,故为ListNode<T>** pHead) ListNode<T>* _list_merge_sort(ListNode<T>** pHead) { if(NULL == *pHead || NULL == (*pHead)->next) return *pHead; ListNode<T>* pSlow = *pHead; ListNode<T>* pFast = *pHead; while(pFast->next !=NULL && pFast->next->next !=NULL) { pSlow = pSlow->next; pFast = pFast->next->next; } ListNode<T>* pLeftHead = *pHead; ListNode<T>* pRightHead = pSlow->next; pSlow->next = NULL;//左半链表尾节点的next赋空值 /*pLeftHead = */_list_merge_sort(&pLeftHead); /*pRightHead = */_list_merge_sort(&pRightHead); //注意:虽然传值,但是内部状态可变,因此pLeftHead和pRightHead内部 //的的next可能已经变了,因此他们可能伸长或缩短 *pHead = list_merge(pLeftHead,pRightHead);//修改头指针 return *pHead; } public: //归并排序入口,去掉了返回值,不包装这一层也行 void list_merge_sort(ListNode<T>** pHead) { _list_merge_sort(pHead);//注意这里传入的是地址 } }; //链表快速排序(测试样例) void test_list_qsort() { //创建结点 ListNode<double>* pNode1 = create_list_node<double>(1.8); ListNode<double>* pNode2 = create_list_node<double>(7.3); ListNode<double>* pNode3 = create_list_node<double>(2.6); ListNode<double>* pNode4 = create_list_node<double>(6); ListNode<double>* pNode5 = create_list_node<double>(-5.8); ListNode<double>* pNode6 = create_list_node<double>(99.5); ListNode<double>* pNode7 = create_list_node<double>(13); ListNode<double>* pNode8 = create_list_node<double>(45); ListNode<double>* pNode9 = create_list_node<double>(-7); //连接结点 connect_list_node(pNode1,pNode2); connect_list_node(pNode2,pNode3); connect_list_node(pNode3,pNode4); connect_list_node(pNode4,pNode5); connect_list_node(pNode5,pNode6); connect_list_node(pNode6,pNode7); connect_list_node(pNode7,pNode8); connect_list_node(pNode8,pNode9); //打印链表 cout<<"原链表: ";print_list(pNode1); //快速排序 List_qsort<double> test_qsort; test_qsort.list_qsort(pNode1);//传值 //test_qsort.list_qsort(&pNode1);//传指针 //test_qsort.list_qsort(pNode1);//传引用 cout<<"排序后: ";print_list(pNode1); /**********销毁链表(我们一般用到的方法,会出现空悬指针)********************/ // destory_list(&pNode1); // //注意,释放链表后,头结点为NULL,其余的虽然释放了,但地址还在,因此成为空悬指针,需要进一步释放 // //从这个角度来看,还不如写个函数释放每个节点,因此写了一个 // if(pNode1) // print_list(pNode1); // else // cout<<"-1"<<endl; /***********************************************************************/ /****************销毁链表(逐个销毁,不会出现空悬指针)*********************/ destory_Node(&pNode1); destory_Node(&pNode2); destory_Node(&pNode3); destory_Node(&pNode4); destory_Node(&pNode5); destory_Node(&pNode6); destory_Node(&pNode7); destory_Node(&pNode8); destory_Node(&pNode9); // if(pNode1) // print_list(pNode1); // else // cout<<"-1"<<endl; /***********************************************************************/ } //链表插入排序(测试样例) void test_list_insertion_sort() { //创建结点 ListNode<double>* pNode1 = create_list_node<double>(1.8); ListNode<double>* pNode2 = create_list_node<double>(7.3); ListNode<double>* pNode3 = create_list_node<double>(2.6); ListNode<double>* pNode4 = create_list_node<double>(6); ListNode<double>* pNode5 = create_list_node<double>(-5.8); ListNode<double>* pNode6 = create_list_node<double>(99.5); ListNode<double>* pNode7 = create_list_node<double>(13); ListNode<double>* pNode8 = create_list_node<double>(45); ListNode<double>* pNode9 = create_list_node<double>(-7); //连接结点 connect_list_node(pNode1,pNode2); connect_list_node(pNode2,pNode3); connect_list_node(pNode3,pNode4); connect_list_node(pNode4,pNode5); connect_list_node(pNode5,pNode6); connect_list_node(pNode6,pNode7); connect_list_node(pNode7,pNode8); connect_list_node(pNode8,pNode9); //打印链表 cout<<"原链表: ";print_list(pNode1); //插入排序 List_insertion_sort<double> test_insertion_sort; test_insertion_sort.list_insert_sort(&pNode1);//传指针 //test_insertion_sort.list_insert_sort(pNode1);//传引用 cout<<"排序后: ";print_list(pNode1); } //链表归并排序(测试样例) void test_list_merge_sort() { //创建结点 ListNode<double>* pNode1 = create_list_node<double>(1.8); ListNode<double>* pNode2 = create_list_node<double>(7.3); ListNode<double>* pNode3 = create_list_node<double>(2.6); ListNode<double>* pNode4 = create_list_node<double>(6); ListNode<double>* pNode5 = create_list_node<double>(-5.8); ListNode<double>* pNode6 = create_list_node<double>(99.5); ListNode<double>* pNode7 = create_list_node<double>(13); ListNode<double>* pNode8 = create_list_node<double>(45); ListNode<double>* pNode9 = create_list_node<double>(-7); //连接结点 connect_list_node(pNode1,pNode2); connect_list_node(pNode2,pNode3); connect_list_node(pNode3,pNode4); connect_list_node(pNode4,pNode5); connect_list_node(pNode5,pNode6); connect_list_node(pNode6,pNode7); connect_list_node(pNode7,pNode8); connect_list_node(pNode8,pNode9); //打印链表 cout<<"原链表: ";print_list(pNode1); //归并排序 List_merge_sort<double> test_merge_sort; //ListNode<double>* p=test_merge_sort.list_merge_sort(&pNode1);//传指针 test_merge_sort.list_merge_sort(&pNode1); cout<<"排序后: ";print_list(pNode1); } int main() { cout<<"测试程序:"<<endl<<endl; cout<<"链表快速排序:"<<endl; test_list_qsort(); cout<<endl; cout<<"链表插入排序:"<<endl; test_list_insertion_sort(); cout<<endl; cout<<"链表归并排序:"<<endl; test_list_merge_sort(); cout<<endl; return 0; }
View Code
总结
链表的操作都基于指针,我们可以通过编写其各种排序代码练习对指针的操作,如指针的指针,指针的引用等。另外,我这里只是演示了三种排序方法,如果有错误敬请指正。大家可试试编写几种其他的排序方法。
参考文章
单链表排序----快排 & 归并排序http://blog.csdn.net/u012658346/article/details/51141288深入单链表的快速排序详解 http://www.jb51.net/article/37300.htm
一步一步写算法(之链表排序)http://blog.csdn.net/feixiaoxing/article/details/6905260/
算法题——单链表的归并排序http://www.cnblogs.com/qieerbushejinshikelou/archive/2014/08/17/3917302.html
在此对以上文章作者表示感谢。欢迎交流。
相关文章推荐
- STL:原地归并排序模板(InplaceMergeSort)
- Merge Sort [Basic] C程序 实现排序功能
- 单链表的排序 快速排序 归并排序 quicksort mergesort
- 插入排序(insert_sort)与 并归排序(merge_sort) 算法分析
- [LeetCode]Sort List 链表排序 + Merge Two Sorted List 合并两个有序链表
- Python中的排序方法(Bubble Sort,Insert Sort,Select Sort,Merge Sort,Quick Sort)
- 【LeetCode】Sort List 链表排序- Medium ++(Merge&Quick Sort)
- sort&qsort排序使用
- Qsort和Sort排序函数用法
- C++ 排序函数 sort(),qsort()的含义与用法 ,字符串string 的逆序排序等
- [STL] 排序函数sort和qsort的用法与区别
- LeetCode | Insertion Sort List(插入法排序链表)
- sort 排序程序的帮助文档
- Algorithms: Merge Sort -- 归并排序
- 快速排序的库函数qsort与sort的使用方法
- LeetCode 148. Sort List--O(nlogn)时间复杂度和常数空间复杂度给链表排序
- C++ 排序函数 sort(),qsort()的用法
- 合并(归并)排序(MergeSort)
- sort(排序) qsort(快排) bsearch(二分查找)
- LeetCode-Insertion Sort List-链表插入排序-链表操作