基于单链表的快排

来源:互联网 发布:k均值聚类算法matlab 编辑:程序博客网 时间:2024/05/16 18:05


来自: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);

}

 

0 0
原创粉丝点击