前言

本文章整理了链表排序的三种方法,分别是快速排序、插入排序、归并排序。为适应不同用途,先给出常用的int版本,再在此基础上抽象出类模板。

目录

一、针对整数的版本(常用)

  1. 文中链表定义
  2. 链表相关操作
  3. 三种排序方法
  4. 完整测试程序

二、模板版本(适用性广泛)

  1. 文中链表定义
  2. 链表相关操作
  3. 三种排序方法
  4. 完整测试程序

总结

参考文章

一、针对整数的版本(常用)

文中链表定义:

 //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(-);//辅助头结点
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.
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(-);//辅助头结点
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);//注意这里传入的是地址
}
}; //链表快速排序(测试样例)
void test_list_qsort()
{
//创建结点
ListNode* pNode1 = create_list_node();
ListNode* pNode2 = create_list_node();
ListNode* pNode3 = create_list_node();
ListNode* pNode4 = create_list_node();
ListNode* pNode5 = create_list_node(-);
ListNode* pNode6 = create_list_node();
ListNode* pNode7 = create_list_node();
ListNode* pNode8 = create_list_node();
ListNode* pNode9 = create_list_node(-); //连接结点
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); //打印链表
print_list(pNode1); //快速排序
List_qsort test_qsort;
test_qsort.list_qsort(pNode1);//传值
//test_qsort.list_qsort(&pNode1);//传指针
//test_qsort.list_qsort(pNode1);//传引用 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* pNode1 = create_list_node();
ListNode* pNode2 = create_list_node();
ListNode* pNode3 = create_list_node();
ListNode* pNode4 = create_list_node();
ListNode* pNode5 = create_list_node(-);
ListNode* pNode6 = create_list_node();
ListNode* pNode7 = create_list_node();
ListNode* pNode8 = create_list_node();
ListNode* pNode9 = create_list_node(-); //连接结点
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); //打印链表
print_list(pNode1); //插入排序
List_insertion_sort test_insertion_sort;
test_insertion_sort.list_insert_sort(&pNode1);//传指针
//test_insertion_sort.list_insert_sort(pNode1);//传引用 print_list(pNode1);
} //链表归并排序(测试样例)
void test_list_merge_sort()
{
//创建结点
ListNode* pNode1 = create_list_node(-);
ListNode* pNode2 = create_list_node(-);
ListNode* pNode3 = create_list_node();
ListNode* pNode4 = create_list_node();
ListNode* pNode5 = create_list_node(-);
ListNode* pNode6 = create_list_node();
ListNode* pNode7 = create_list_node(-);
ListNode* pNode8 = create_list_node();
//ListNode* pNode9 = create_list_node(-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); //打印链表
print_list(pNode1); //归并排序
List_merge_sort test_merge_sort;
//ListNode* p=test_merge_sort.list_merge_sort(&pNode1);//传指针
test_merge_sort.list_merge_sort(&pNode1); 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 ; return ;
}

二、模板版本(适用性广泛)

文中链表定义:

 //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>(-);//辅助头结点
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);//注意这里传入的是地址
}
};

完整测试程序:

 /*
本程序说明: 链表排序各种方法(快速排序) 参考链接:
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>(-);//辅助头结点
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>();
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>();
ListNode<double>* pNode8 = create_list_node<double>();
ListNode<double>* pNode9 = create_list_node<double>(-); //连接结点
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>();
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>();
ListNode<double>* pNode8 = create_list_node<double>();
ListNode<double>* pNode9 = create_list_node<double>(-); //连接结点
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>();
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>();
ListNode<double>* pNode8 = create_list_node<double>();
ListNode<double>* pNode9 = create_list_node<double>(-); //连接结点
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 ;
}

总结

链表的操作都基于指针,我们可以通过编写其各种排序代码练习对指针的操作,如指针的指针,指针的引用等。

另外,我这里只是演示了三种排序方法,如果有错误敬请指正。大家可试试编写几种其他的排序方法。

参考文章

在此对以上文章作者表示感谢。欢迎交流。

【模板小程序】链表排序(qsort/insert_sort/merge_sort)的更多相关文章

  1. 模板小程序】求小于等于N范围内的质数

    xiaoxi666 联系邮箱: xiaoxi666swap@163.com 博客园 首页 新随笔 联系 订阅 管理 [模板小程序]求小于等于N范围内的质数   1 //筛法求N以内的素数(普通法+优化 ...

  2. 【模板小程序】求小于等于N范围内的质数

    //筛法求N以内的素数(普通法+优化),N>=2 #include <iostream> #include <cmath> #include <vector> ...

  3. 【模板小程序】求M~N范围内的质数个数

    /* 本程序说明: [编程题] 求素数 时间限制:2秒 空间限制:32768K 输入M.N,1 < M < N < 1000000,求区间[M,N]内的所有素数的个数.素数定义:除了 ...

  4. 【模板小程序】循环方阵构造(仿《剑指offer》循环矩阵打印)

    /* 本程序说明: 输入:方阵大小n,输出:n*n的旋转方阵 举例: 当n=2时,输出: 1 2 4 3 当n=4时,输出: 1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 ...

  5. 【模板小程序】求第n个fibonacci数

    //fibonacci,find the nth num. 1 1 2 3 5 8... #include <iostream> using namespace std; int fib( ...

  6. 【模板小程序】求第n个质数

    #include <iostream> #include <vector> using namespace std; int nth_prime(int n) { vector ...

  7. 【模板小程序】任意长度非负十进制数转化为二进制(java实现)

    妈妈再也不用担心十进制数过大了233(注意只支持非负数) import com.google.common.base.Strings; import java.math.BigInteger; imp ...

  8. 微信小程序学习指南

    作者:初雪链接:https://www.zhihu.com/question/50907897/answer/128494332来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...

  9. “我的小程序”来了 新版微信v6.7.1下拉就能找到

    今天iOS版微信迎来v6.7.1正式版发布,本次升级主要是可以把常用的小程序添加到“我的小程序”.近期版本微信可以直接浏览订阅号的消息,扫一扫可拍照翻译整页中英文,浏览的文章支持缩小为浮窗.两大更新如 ...

随机推荐

  1. Css实现一个简单的幻灯片效果页面

    使用animation动画实现一个简单的幻灯片效果. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 2 ...

  2. AngularJS的文字溢出处理

    需求大致如图所示,由于本人也是新接触AngularJS,研究好久,制作了一个demo,代码如下: <!DOCTYPE html><html><head><me ...

  3. 不带插件 ,自己写js,实现批量上传文件及进度显示

    今天接受项目中要完成文件批量上传文件而且还要显示上传进度,一开始觉得这个应该不是很麻烦,当我在做的时候遇到了很多问题,很头疼啊. 不过看了别人写的代码,自己也测试过,发现网上好多都存在一些问题,并不是 ...

  4. Oracle数据库web维护客户端管理工具软件

    TreeSoft数据库管理系统使用JAVA开发,采用稳定通用的springMVC +JDBC架构,实现基于WEB方式对 MySQL,Oracle,PostgreSQL 等数据库进行维护管理操作. 功能 ...

  5. uwp版的音乐播放器练手

    UWP项目之音乐播放器 这个项目本来是我女朋友的一个小作业,她做不出来,结果只能是我来代劳.经过几天的时间虽然赶出来了,但是自己不是很满意,还有很多不满意的地方,因此决定在最近的一段时间内,重新完成. ...

  6. Petya勒索病毒疫苗出现,分分钟让电脑对病毒免疫

    继wannacry之后,Petya勒索软件攻击再次席卷全球,对欧洲.俄罗斯等多国政府.银行.电力系统.通讯系统.企业以及机场造成了不同程度的影响. 研究发现,Petya 会锁定磁盘的 MFT 和 MB ...

  7. java注解编程

  8. 彩扩机项目--NPN和PNP三极管作为开关管的区别

    上图是最终画好的电路.使用的是NPN三极管,并且把NPN三极管放在了下面.下面分析下NPN三极管作为开关管能否放在上面. 从上面两张图分析可知,当三极管作为开关管使用的时候,NPN三极管需要放在下面( ...

  9. java udp服务器设计源码

    根据个人理解写的,轻喷. 没什么大的逻辑,直接上代码. UDPServer.java package mySocket;/* * 服务器端 */import java.awt.GridLayout;i ...

  10. nyoj_762:第k个互质数

    题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=762 直接给代码好了,容斥原理具体看<组合数学> #include<bi ...