【模板小程序】链表排序(qsort/insert_sort/merge_sort)
前言
本文章整理了链表排序的三种方法,分别是快速排序、插入排序、归并排序。为适应不同用途,先给出常用的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(-);//辅助头结点
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 ;
}
总结
链表的操作都基于指针,我们可以通过编写其各种排序代码练习对指针的操作,如指针的指针,指针的引用等。
另外,我这里只是演示了三种排序方法,如果有错误敬请指正。大家可试试编写几种其他的排序方法。
参考文章
- 单链表排序----快排 & 归并排序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
在此对以上文章作者表示感谢。欢迎交流。
【模板小程序】链表排序(qsort/insert_sort/merge_sort)的更多相关文章
- 模板小程序】求小于等于N范围内的质数
xiaoxi666 联系邮箱: xiaoxi666swap@163.com 博客园 首页 新随笔 联系 订阅 管理 [模板小程序]求小于等于N范围内的质数 1 //筛法求N以内的素数(普通法+优化 ...
- 【模板小程序】求小于等于N范围内的质数
//筛法求N以内的素数(普通法+优化),N>=2 #include <iostream> #include <cmath> #include <vector> ...
- 【模板小程序】求M~N范围内的质数个数
/* 本程序说明: [编程题] 求素数 时间限制:2秒 空间限制:32768K 输入M.N,1 < M < N < 1000000,求区间[M,N]内的所有素数的个数.素数定义:除了 ...
- 【模板小程序】循环方阵构造(仿《剑指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 ...
- 【模板小程序】求第n个fibonacci数
//fibonacci,find the nth num. 1 1 2 3 5 8... #include <iostream> using namespace std; int fib( ...
- 【模板小程序】求第n个质数
#include <iostream> #include <vector> using namespace std; int nth_prime(int n) { vector ...
- 【模板小程序】任意长度非负十进制数转化为二进制(java实现)
妈妈再也不用担心十进制数过大了233(注意只支持非负数) import com.google.common.base.Strings; import java.math.BigInteger; imp ...
- 微信小程序学习指南
作者:初雪链接:https://www.zhihu.com/question/50907897/answer/128494332来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- “我的小程序”来了 新版微信v6.7.1下拉就能找到
今天iOS版微信迎来v6.7.1正式版发布,本次升级主要是可以把常用的小程序添加到“我的小程序”.近期版本微信可以直接浏览订阅号的消息,扫一扫可拍照翻译整页中英文,浏览的文章支持缩小为浮窗.两大更新如 ...
随机推荐
- 学习mysql语法--基础篇(一)
前 言 mysql mysql语法--本篇学习都是通过使用Navicat Premium(数据库管理工具),连接mysql数据. 本篇学习主要有两个部分: 一.创建用户,创建数据库,给 ...
- 关于MATLAB处理大数据坐标文件
原先有3000条测试数据,MATLAB表现出来强大的数据处理能力,十几秒就可以把数据分类.分装并储存,这次共有10万条坐标数据,MATLAB明显后劲不足,显示内存不足 自我认识:以前MATLAB数据处 ...
- Xcode9新特性介绍-中文篇
背景: Xcode 9 新特性介绍: 1.官方原文介绍链接 2.Xcode9 be ta 2 官方下载链接 本文为官方介绍翻译而来,布局排版等都是按照官方布局来的. 与原文相比,排版上基本还是熟悉的配 ...
- html模板中的数字保留两位小数
<script> //html模板中的数字保留两位小数 function formatCurrency(num) { num = num.toString().replace(/\$|\, ...
- 【Android Developers Training】 20. 创建一个Fragment
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- 设备像素比dpr介绍
首先介绍一下概念 devicePixelRatio其实指的是window.devicePixelRatio window.devicePixelRatio是设备上物理像素和设备独立像素(device- ...
- PHP连接数据库、创建数据库、创建表的三种方式
这篇博客主要介绍了三种方式来连接MySQL数据库以及创建数据库.创建表.(代码是我在原来的基础上改的) MySQLi - 面向对象 MySQLi - 面向过程 PDO MySQLi 面向对象 < ...
- WM_COPYDATA传送指针数据类型的问题
WM_COPYDATA传送指针数据的问题 var cdds:TcopyDataStruct; strAnsi:string;begin cdds:=PCopyDataSt ...
- Spring DelegatingFilterProxy解析
以前DelegatingFilterProxy是在需要使用spring security 的时候在xml中配置,如下: <filter> <filter-name>spring ...
- MYSQL的日志与备份还原
一.错误日志 当数据库出现任何故障导致无法使用时,第一时间先去查看该日志 1.服务器启动关闭过程中的信息 2.服务器运行过程中的错误信息 日志存放路径,可以通过命令查看: 日志文件命名格式:host_ ...