您的位置:首页 > 其它

基于单链表的快排

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);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: