您的位置:首页 > 移动开发 > 微信开发

【模板小程序】链表排序(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

在此对以上文章作者表示感谢。欢迎交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: