基于单链表的快排
2016-09-12 23:14
162 查看
来自:http://blog.sina.com.cn/s/blog_8d2b43b50101c6wk.html
单链表的快排序和数组的快排序基本思想相同,同样是基于划分,但是又有很大的不同:单链表不支持基于下标的访问。但是,由于单链表不能像数组那样随机存储,和数组的快排序相比较,还是有一些需要注意的细节:
1、支点的选取,由于不能随机访问第K个元素,因此每次选择支点时可以取待排序那部分链表的头指针。
2、遍历量表方式,由于不能从单链表的末尾向前遍历,因此使用两个指针分别向前向后遍历的策略实效,
有两种方式实现单链表的快速排序:
第一种是调整节点的next域。选择链表的第一个节点作为基准,然后进行比较,比基准小得节点放入左面的子链表,比基准大的放入右边的子链表。在对待排序链表扫描一遍之后,左面子链表的节点值都小于基准的值,右边子链表的值都大于基准的值,然后把基准插入到链表中,并作为连接两个子链表的桥梁。
Node *Partition(Node **ypBegin, Node *pEnd)
{
Node **ypLeftWalk = NULL;
Node **ypRightWalk = NULL;
Node *pWalk = NULL;
Node *pPivot = NULL;
ypLeftWalk = ypBegin;
pPivot = *ypBegin;
ypRightWalk = &(pPivot->pNext);
for (pWalk=(*ypBegin)->pNext; pWalk!=pEnd; pWalk=pWalk->pNext)
{
if (pWalk->data < pPivot->data)
{
*ypLeftWalk=pWalk;
ypLeftWalk=&(pWalk->pNext);
}
else
{
*ypRightWalk=pWalk;
ypRightWalk=&(pWalk->pNext);
}
}
*ypRightWalk = pEnd;
*ypLeftWalk = pPivot;
return pPivot;
}
void QuickSort(Node **pHead, Node *pEnd)
{
if ( *pHead != pEnd)
{
Node *pPivot = Partition(pHead, pEnd);
QuickSort(pHead, pPivot);
QuickSort(&(pPivot->pNext), pEnd);
}
}
也可以用一个函数实现递归:
void QuickSortForLinkList(Node **ypHead, Node *pEnd)
{
if (*ypHead==pEnd || (*ypHead)->pNext==pEnd)
{
return;
}
Node **ypLeftWalk = NULL;
Node **ypRightWalk = NULL;
Node *pWalk = NULL;
Node *pPivot = NULL;
ypLeftWalk = ypHead;
pPivot = *ypHead;
ypRightWalk = &(pPivot->pNext);
for (pWalk=(*ypHead)->pNext; pWalk!=pEnd; pWalk=pWalk->pNext)
{
if (pWalk->data < pPivot->data)
{
*ypLeftWalk=pWalk;
ypLeftWalk=&(pWalk->pNext);
}
else
{
*ypRightWalk=pWalk;
ypRightWalk=&(pWalk->pNext);
}
}
*ypRightWalk = pEnd;
*ypLeftWalk = pPivot;
QuickSortForLinkList(ypHead,pPivot);
QuickSortForLinkList(&(pPivot->pNext),pEnd);
}
调用方式为:QuickSort(&pHead, NULL), QuickSortForLinkList(&pHead, NULL)
第二种是交换节点的值域。需要两个指针p和q,这两个指针均往next方向移动,移动的过程中保持p之前的key都小于选定的key,p和q之间的key都大于选定的key,那么当q走到末尾的时候便完成了一次枢轴点位置的寻找,进而将枢轴点复制到合适的节点处。具体做法是:
1)定义两个指针pLeft,pRight,其中pLeft指向单链表的头结点,pRight指向单链表头结点的下一个结点;
2)使用pRight遍历单链表,每遇到一个比支点小的元素,就令pLeft=pLeft->pNext,然后和pRight进行数据交换。
// Exchange the node data to quick sort Linklist through two functions
void Swap(int &p, int &q)
{
if (p == q)
return;
q = p ^ q;
p = p ^ q;
q = p ^ q;
}
Node* Partition(Node* pBegin, Node* pEnd)
{
int data = pBegin->data;
Node* pLeft = pBegin;
Node* pRight = pLeft->pNext;
while (pRight != pEnd)
{
if (pRight->data < data)
{
pLeft = pLeft->pNext;
Swap(pLeft->data, pRight->data);
}
pRight = pRight->pNext;
}
Swap(pLeft->data, pBegin->data);
return pLeft;
}
void QuickSort(Node* pBeign, Node* pEnd)
{
if(pBeign != pEnd)
{
Node* partion = Partition(pBeign,pEnd);
QuickSort(pBeign,partion);
QuickSort(partion->pNext, pEnd);
}
}
一种调用方式(即测试方法):
#include
#include
using namespace std;
struct Node
{
int data;
Node *pNext;
};
void PrintList(Node *pHead)
{
if (pHead == NULL)
return ;
Node *p = pHead->pNext ;
while ( p != NULL )
{
cout<<p->data<<" ";
p = p->pNext;
}
cout<<endl;
}
void TestListQuick()
{
Node *pHead = NULL;
pHead = new Node;
pHead->pNext = NULL;
pHead ->data = 0;
Node *p = NULL;
srand((unsigned)time(NULL));
for(int i=0; i<12; i++)
{
p = new Node;
p->data = rand()/100 +1;
p->pNext = pHead->pNext;
pHead->pNext = p;
}
PrintList(pHead);
cout<<"*********************************"<<endl;
QuickSort(pHead->pNext, NULL);
//QuickSort(&(pHead->pNext), NULL);
PrintList(pHead);
}
单链表的快排序和数组的快排序基本思想相同,同样是基于划分,但是又有很大的不同:单链表不支持基于下标的访问。但是,由于单链表不能像数组那样随机存储,和数组的快排序相比较,还是有一些需要注意的细节:
1、支点的选取,由于不能随机访问第K个元素,因此每次选择支点时可以取待排序那部分链表的头指针。
2、遍历量表方式,由于不能从单链表的末尾向前遍历,因此使用两个指针分别向前向后遍历的策略实效,
有两种方式实现单链表的快速排序:
第一种是调整节点的next域。选择链表的第一个节点作为基准,然后进行比较,比基准小得节点放入左面的子链表,比基准大的放入右边的子链表。在对待排序链表扫描一遍之后,左面子链表的节点值都小于基准的值,右边子链表的值都大于基准的值,然后把基准插入到链表中,并作为连接两个子链表的桥梁。
Node *Partition(Node **ypBegin, Node *pEnd)
{
Node **ypLeftWalk = NULL;
Node **ypRightWalk = NULL;
Node *pWalk = NULL;
Node *pPivot = NULL;
ypLeftWalk = ypBegin;
pPivot = *ypBegin;
ypRightWalk = &(pPivot->pNext);
for (pWalk=(*ypBegin)->pNext; pWalk!=pEnd; pWalk=pWalk->pNext)
{
if (pWalk->data < pPivot->data)
{
*ypLeftWalk=pWalk;
ypLeftWalk=&(pWalk->pNext);
}
else
{
*ypRightWalk=pWalk;
ypRightWalk=&(pWalk->pNext);
}
}
*ypRightWalk = pEnd;
*ypLeftWalk = pPivot;
return pPivot;
}
void QuickSort(Node **pHead, Node *pEnd)
{
if ( *pHead != pEnd)
{
Node *pPivot = Partition(pHead, pEnd);
QuickSort(pHead, pPivot);
QuickSort(&(pPivot->pNext), pEnd);
}
}
也可以用一个函数实现递归:
void QuickSortForLinkList(Node **ypHead, Node *pEnd)
{
if (*ypHead==pEnd || (*ypHead)->pNext==pEnd)
{
return;
}
Node **ypLeftWalk = NULL;
Node **ypRightWalk = NULL;
Node *pWalk = NULL;
Node *pPivot = NULL;
ypLeftWalk = ypHead;
pPivot = *ypHead;
ypRightWalk = &(pPivot->pNext);
for (pWalk=(*ypHead)->pNext; pWalk!=pEnd; pWalk=pWalk->pNext)
{
if (pWalk->data < pPivot->data)
{
*ypLeftWalk=pWalk;
ypLeftWalk=&(pWalk->pNext);
}
else
{
*ypRightWalk=pWalk;
ypRightWalk=&(pWalk->pNext);
}
}
*ypRightWalk = pEnd;
*ypLeftWalk = pPivot;
QuickSortForLinkList(ypHead,pPivot);
QuickSortForLinkList(&(pPivot->pNext),pEnd);
}
调用方式为:QuickSort(&pHead, NULL), QuickSortForLinkList(&pHead, NULL)
第二种是交换节点的值域。需要两个指针p和q,这两个指针均往next方向移动,移动的过程中保持p之前的key都小于选定的key,p和q之间的key都大于选定的key,那么当q走到末尾的时候便完成了一次枢轴点位置的寻找,进而将枢轴点复制到合适的节点处。具体做法是:
1)定义两个指针pLeft,pRight,其中pLeft指向单链表的头结点,pRight指向单链表头结点的下一个结点;
2)使用pRight遍历单链表,每遇到一个比支点小的元素,就令pLeft=pLeft->pNext,然后和pRight进行数据交换。
// Exchange the node data to quick sort Linklist through two functions
void Swap(int &p, int &q)
{
if (p == q)
return;
q = p ^ q;
p = p ^ q;
q = p ^ q;
}
Node* Partition(Node* pBegin, Node* pEnd)
{
int data = pBegin->data;
Node* pLeft = pBegin;
Node* pRight = pLeft->pNext;
while (pRight != pEnd)
{
if (pRight->data < data)
{
pLeft = pLeft->pNext;
Swap(pLeft->data, pRight->data);
}
pRight = pRight->pNext;
}
Swap(pLeft->data, pBegin->data);
return pLeft;
}
void QuickSort(Node* pBeign, Node* pEnd)
{
if(pBeign != pEnd)
{
Node* partion = Partition(pBeign,pEnd);
QuickSort(pBeign,partion);
QuickSort(partion->pNext, pEnd);
}
}
一种调用方式(即测试方法):
#include
#include
using namespace std;
struct Node
{
int data;
Node *pNext;
};
void PrintList(Node *pHead)
{
if (pHead == NULL)
return ;
Node *p = pHead->pNext ;
while ( p != NULL )
{
cout<<p->data<<" ";
p = p->pNext;
}
cout<<endl;
}
void TestListQuick()
{
Node *pHead = NULL;
pHead = new Node;
pHead->pNext = NULL;
pHead ->data = 0;
Node *p = NULL;
srand((unsigned)time(NULL));
for(int i=0; i<12; i++)
{
p = new Node;
p->data = rand()/100 +1;
p->pNext = pHead->pNext;
pHead->pNext = p;
}
PrintList(pHead);
cout<<"*********************************"<<endl;
QuickSort(pHead->pNext, NULL);
//QuickSort(&(pHead->pNext), NULL);
PrintList(pHead);
}
相关文章推荐
- 单链表中基于箱子的基数排序
- 基于链表:输入若干整数以单链表形式存储起来,然后计算单链表中结点的个数
- 基于单链表实现一元n次多项式的创建、输出和求和操作
- 单链表中基于箱子的基数排序
- 基于单链表的面试题-基础篇
- 基于C语言单链表的成绩管理程序
- 基于Linux C 单链表的通讯录程序
- Python 使用单链表实现堆栈 (基于class, 包含迭代器)
- 单链表中基于箱子的基数排序
- 基于单链表的直接插入排序
- 排序之基于单链表插入排序
- 基于单链表的冒泡排序简易学生成绩排序程序
- 基于单链表的链队列
- 单链表中基于箱子的基数排序
- 单链表中基于箱子的基数排序
- 基于单链表的两个非递减有序表的合并
- 单链表中基于箱子的基数排序
- 单链表中基于箱子的基数排序
- 基于单链表的生产者消费者问题