单链表的快速排序

方法一:

单链表的快速排序和数组的快速排序在基本细想上是一致的,以从小到大来排序单链表为例,都是选择一个支点,然后把小于支点的元素放到左边,把大于支点的元素放到右边。但是,由于单链表不能像数组那样随机存储,和数组的快排序相比较,还是有一些需要注意的细节:

1. 支点的选取,由于不能随机访问第K个元素,因此每次选择支点时可以取待排序那部分链表的头指针。

2. 遍历量表方式,由于不能从单链表的末尾向前遍历,因此使用两个指针分别向前向后遍历的策略实效,

    事实上,可以可以采用一趟遍历的方式将较小的元素放到单链表的左边。具体方法为:

    1)定义两个指针pslow, pfast,其中pslow指单链表头结点,pfast指向单链表头结点的下一个结点;

    2)使用pfast遍历单链表,每遇到一个比支点小的元素,就和pslow进行数据交换,然后令pslow=pslow->next。

3. 交换数据方式,直接交换链表数据指针指向的部分,不必交换链表节点本身。

void sort_slist(SList* phead, SList* pend)
{
if(phead == NULL || pend == NULL) return;
if(phead == pend) return;
SList* pslow = phead;
SList* pfast = phead->next;
SList* ptemp = phead; 
while(pfast && pfast != pend->next)
{
   if(pfast->data <= phead->data) //phead作为支点

   {
    ptemp = pslow;
    pslow = pslow->next;
    swap(pslow->data, pfast->data);
   }
   pfast = pfast->next;
}
swap(phead->data, pslow->data);

sort_slist(phead, ptemp);//ptemp为左右两部分分割点的前一个节点
sort_slist(pslow->next, pend);

}
方法二:

可以把待排序的链表拆分为2个子链表。为了简单起见,选择链表的第一个节点作为基准,然后进行比较,比基准大节点的放入左面的子链表,比基准大的放入右边的子链表。在对待排序链表扫描一遍之后,左面子链表的节点值都小于基准的值,右边子链表的值都大于基准的值,然后把基准插入到链表中,并作为连接两个子链表的桥梁。然后根据左右子链表中节点数,选择较小的进行递归快速排序,而对数目较多的则进行迭代等排序,以提高性能。

  1. /** 
  2. * 单链表的快排序 
  3. * author :blue 
  4. * data   :2010-4-6 
  5. */  
  6.   
  7. #include <stdio.h>  
  8. #include <stdlib.h>  
  9. #include <time.h>  
  10. //链表节点  
  11. struct node {  
  12.     int data;  
  13.     struct node *next;  
  14. };  
  15. //链表快排序函数  
  16. void QListSort(struct node **head, struct node *head);  
  17. //打印链表  
  18. void print_list(struct node *head) {  
  19.     struct node *p;  
  20.     for (p = head; p != NULL; p = p->next) {  
  21.         printf("%d ", p->data);  
  22.     }  
  23.     printf("/n");  
  24. }  
  25. int main(void) {  
  26.     struct node *head;  
  27.     struct node *p;  
  28.     int i = 0;  
  29.     /** 
  30.     * 初始化链表 
  31.     */  
  32.     head = (struct node*)malloc(sizeof(struct node));  
  33.     head->next = NULL;  
  34.     head->data = 0;  
  35.     srand((unsigned)time(NULL));  
  36.     for (i = 1; i < 11; ++i) {  
  37.         p = (struct node*)malloc(sizeof(struct node));  
  38.         p->data = rand() % 100 + 1;  
  39.         p->next = head->next;  
  40.         head->next = p;  
  41.     }  
  42.       
  43.     print_list(head);  
  44.     printf("---------------------------------/n");  
  45.     QListSort(&head, NULL);  
  46.     print_list(head);  
  47.     return 0;  
  48. }  
  49.   
  50. void QListSort(struct node **head, struct node *end) {  
  51.     struct node *right;  
  52.     struct node **left_walk, **right_walk;  
  53.     struct node *pivot, *old;  
  54.     int count, left_count, right_count;  
  55.     if (*head == end)  
  56.         return;  
  57.     do {  
  58.         pivot = *head;  
  59.         left_walk = head;  
  60.         right_walk = &right;  
  61.         left_count = right_count = 0;  
  62.         //取第一个节点作为比较的基准,小于基准的在左面的子链表中,  
  63.         //大于基准的在右边的子链表中  
  64.         for (old = (*head)->next; old != end; old = old->next) {  
  65.             if (old->data < pivot->data) {   //小于基准,加入到左面的子链表,继续比较  
  66.                 ++left_count;  
  67.                 *left_walk = old;            //把该节点加入到左边的链表中,  
  68.                 left_walk = &(old->next);  
  69.             } else {                         //大于基准,加入到右边的子链表,继续比较  
  70.                 ++right_count;  
  71.                 *right_walk = old;             
  72.                 right_walk = &(old->next);  
  73.             }  
  74.         }  
  75.         //合并链表  
  76.         *right_walk = end;       //结束右链表  
  77.         *left_walk = pivot;      //把基准置于正确的位置上  
  78.         pivot->next = right;     //把链表合并  
  79.         //对较小的子链表进行快排序,较大的子链表进行迭代排序。  
  80.         if(left_walk > right_walk) {  
  81.             QListSort(&(pivot->next), end);  
  82.             end = pivot;  
  83.             count = left_count;  
  84.         } else {  
  85.             QListSort(head, pivot);  
  86.             head = &(pivot->next);  
  87.             count = right_count;  
  88.         }  
  89.     } while (count > 1);   
  90. }  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值