亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

深入單鏈表的快速排序詳解

2020-01-26 16:09:23
字體:
來源:轉載
供稿:網友
單鏈表的快排序和數組的快排序基本思想相同,同樣是基于劃分,但是又有很大的不同:單鏈表不支持基于下標的訪問。故書中把待排序的鏈表拆分為2個子鏈表。為了簡單起見,選擇鏈表的第一個節點作為基準,然后進行比較,比基準小得節點放入左面的子鏈表,比基準大的放入右邊的子鏈表。在對待排序鏈表掃描一遍之后,左邊子鏈表的節點值都小于基準的值,右邊子鏈表的值都大于基準的值,然后把基準插入到鏈表中,并作為連接兩個子鏈表的橋梁。然后分別對左、右兩個子鏈表進行遞歸快速排序,以提高性能。
但是,由于單鏈表不能像數組那樣隨機存儲,和數組的快排序相比較,還是有一些需要注意的細節:

1、支點的選取,由于不能隨機訪問第K個元素,因此每次選擇支點時可以取待排序那部分鏈表的頭指針。
2、遍歷量表方式,由于不能從單鏈表的末尾向前遍歷,因此使用兩個指針分別向前向后遍歷的策略實效,
事實上,可以可以采用一趟遍歷的方式將較小的元素放到單鏈表的左邊。
具體方法為:
1)定義兩個指針pslow,pfast,其中pslow指向單鏈表的頭結點,pfast指向單鏈表頭結點的下一個結點;
2)使用pfast遍歷單鏈表,每遇到一個比支點小的元素,就令pslow=pslow->next,然后和pslow進行數據交換。
3、交換數據方式,直接交換鏈表數據指針指向的部分,不必交換鏈表節點本身。
基于上述思想的單鏈表快速排序實現如下:
復制代碼 代碼如下:

/**  
** 單鏈表的快速排序  
** author :liuzhiwei
** date   :2011-08-07  
**/
#include<iostream>
#include<ctime>
using namespace std;
//單鏈表節點
struct SList
{
    int data;
    struct SList* next;
};
void bulid_slist(SList** phead, int n)    //指向指針的指針
{
    int i;
    SList* ptr = *phead;
    for(i = 0; i < n; ++i)
    {
        SList* temp = new SList;
        temp->data = rand() % n;   //產生n個n以內的隨機數
        temp->next = NULL;
        if(ptr == NULL)
        {
            *phead = temp;
            ptr = temp;
        }
        else
        {
            ptr->next = temp;
            ptr = ptr->next;
        }
    }
}
void print_slist(SList* phead)   //輸出鏈表
{
    SList *ptr = phead;
    while(ptr)
    {
        printf("%d ", ptr->data);
        ptr = ptr->next;
    }
    printf("/n");
}
void my_swap(int *a,int *b)
{
    int temp;
    temp=*a;
    *a=*b;
    *b=temp;
}
void sort_slist(SList* phead, SList* pend)    //將頭指針為phead,尾指針為pend的鏈表進行排序
{
    if(phead == NULL)
        return ;
    if(phead == pend)
        return ;
    SList *pslow = phead;
    SList *pfast = phead->next;
    SList *ptemp = phead;
    while(pfast != pend)
    {
        if(pfast->data < phead->data)        //每次都選擇待排序鏈表的頭結點作為劃分的基準
        {
            ptemp = pslow;          //ptemp始終為pslow的前驅結點
            pslow = pslow->next;
            my_swap(&pslow->data , &pfast->data);       //pslow指針指向比基準小的結點組成的鏈表
        }
        pfast = pfast->next;
    }
    my_swap(&pslow->data , &phead->data);  //此時pslow指針指向比基準小的結點組成的鏈表的最后一個結點,也就是基準的位置,所以要與基準(head結點)交換
    sort_slist(phead , pslow);             //ptemp為左右兩部分分割點(基準)的前一個結點
    sort_slist(pslow->next , NULL);        //右部分是比基準大的結點組成的鏈表
}
void destroy_slist(SList* phead)
{
    SList* ptr = phead;
    while(ptr)
    {
        SList* temp = ptr;
        ptr = ptr->next;
        delete temp;
    }
}
int main(void)
{
    srand(time(NULL));
    printf("Before sort single list/n");
    SList* phead = NULL;
    bulid_slist(&phead, 100);
    print_slist(phead);
    printf("After sort single list/n");
    sort_slist(phead, NULL);
    print_slist(phead);
    destroy_slist(phead);
    system("pause");
    return 0;
}

第二種方法:
選擇鏈表的第一個節點作為基準,然后進行比較,比基準小得節點放入左面的子鏈表,比基準大的放入右邊的子鏈表。在對待排序鏈表掃描一遍之后,左面子鏈表的節點值都小于基準的值,右邊子鏈表的值都大于基準的值,然后把基準插入到鏈表中,并作為連接兩個子鏈表的橋梁。然后根據左、右子鏈表中節點數,選擇較小的進行遞歸快速排序,而對數目較多的則進行迭代排序。
排序函數中使用的變量如下:
復制代碼 代碼如下:

 struct node *right;   //右邊子鏈表的第一個節點
struct node **left_walk, **right_walk;    //作為指針,把其指向的節點加入到相應的子鏈表中
struct node *pivot, *old;    //pivot為基準, old為循環整個待排序鏈表的指針
核心代碼如下:
for (old = (*head)->next; old != end; old = old->next) {
      if (old->data < pivot->data) {  //小于基準,加入到左面的子鏈表,繼續比較
             ++left_count;
         *left_walk = old;            //把該節點加入到左邊的鏈表中,
         left_walk = &(old->next);
} else {                      //大于基準,加入到右邊的子鏈表,繼續比較
         ++right_count;
             *right_walk = old;         
             right_walk = &(old->next);
      }
}

 head為struct node **類型,指向鏈表頭部,end指向鏈表尾部,可為NULL,這段程序的重點在于指針的指針的用法,*left_walk為一個指向node節點的指針,說的明白點*left_walk的值就是node節點的內存地址,其實還有一個地方也有node的地址,那就是指向node的節點的next域,故我們可以簡單的認為*left_walk = old就是把指向node節點的節點的next域改為節點old的地址,這樣可能造成兩種情況:一種就是*left_walk本來就指向old節點,這樣就沒有改變任何改變,另一種則是改變了*right_walk指向節點的前一個節點的next域,使其指向后部的節點,中間跳過了若干個節點,不過在這里這樣做并不會造成任何問題,因為鏈表中的節點要么加入到左面的子鏈表中,要么加入到右面的子鏈表中,不會出現節點丟失的情況。
下面用圖示說明下上面的問題:


這里假設鏈表的值一次是5、2、4、6、1。根據程序首先head = left_walk指向值為5的節點,old指向值為2的節點,2小于5,所以加入2到左面的子鏈表中,*left_walk=old,我們知道,*left_walk指向的是第一個節點,這樣做改變了head指針值,使其指向第二個節點,然后left_walk后移,old后移,4同樣小于5,故繼續上述操作,但是這是*left_walk和old指向的是同一個節點,沒有引起任何變化,left_walk和old后移,6大于5,這時不同就出現了,要把其加入到右邊的子鏈表中,故是*right_walk = old,其實right_walk初試化為&right,這句話相當于right = old,即令old當前指向的節點作為右邊子鏈表的第一個節點,以后大于基準的節點都要加入到這個節點中,且總是加入到尾部。此時right_walk,和old后移,1小于5應該加入到左邊的子鏈表中,*left_walk = old,此時*left_walk指向6,故此語句的作用是更改節點4的next值,把其改為1的地址,這樣6就從原來的鏈表中脫鉤了,繼續left_walk和old后移到9節點,應加入到右邊的子鏈表中,此時*right_walk指向1,故把9節點加入到6節點的后面。

這就是基本的排序過程,然而有一個問題需要搞明白,比如有節點依次為struct node *a, *b, *c,node **p , p = &b,如果此時令*p = c,即實際效果是a->next = c;我們知道這相當于該a的next域的值。而p僅僅是一個指針的指針,它是指向b所指向的節點的地址的指針,那么當我們更改*p的值的時候怎么會改到了a的next呢(這個可以寫程序驗證下,確實如此)?其實并非如此,我們仔細的看看程序,left_walk初始化為head,那么第一次執行*left_walk是把head指向了左邊鏈表的起始節點,然后left_walk被賦值為&(old->next),這句話就有意思了,我們看一看下面在執行*left_walk=old時的情況,可以簡單的來個等價替換,*left_walk = old也就相當于*&(old->next) = old,即old->nex = old,不過這里的old可不一定是old->next所指向的節點,應為left_walk和right_walk都指向它們的old節點,但是卻是不同的。

算法到這里并沒有完,這只是執行了一次劃分,把基準放入了正確的位置,還要繼續,不過下面的就比較簡單了,就是遞歸排序個數比較小的子鏈表,迭代處理節點數目比較大的子鏈表。
完整的代碼如下:

復制代碼 代碼如下:

#include <stdio.h>  
#include <stdlib.h>  
#include <time.h>  
//鏈表節點  
struct node
{
 int data;  
 struct node *next;  
};  
//鏈表快排序函數
void QListSort(struct node **head,struct node *h);  
//打印鏈表  
void print_list(struct node *head)
{
 struct node *p;  
 for (p = head; p != NULL; p = p->next)
 {  
  printf("%d ", p->data);  
 }  
 printf("/n");  
}  
int main(void)
{
 struct node *head = NULL;  
 struct node *p;  
 int i;  
 /** 
 * 初始化鏈表 
 */
 srand((unsigned)time(NULL));  
 for (i = 1; i < 11; ++i)
 {  
  p = (struct node*)malloc(sizeof(struct node));  
  p->data = rand() % 100 + 1;
  if(head == NULL)
  {
   head = p;
   head->next = NULL;
  }
  else
  {
   p->next = head->next;
   head->next = p;
  }
 }
 print_list(head);
 printf("---------------------------------/n");
 QListSort(&head,NULL);
 print_list(head);
 system("pause");
 return 0;  
}  
void QListSort(struct node **head, struct node *end)
{
 struct node *right;  
 struct node **left_walk, **right_walk;  
 struct node *pivot, *old;  
 int count, left_count, right_count;  
 if (*head == end)
  return;  
 do {  
  pivot = *head;  
  left_walk = head;
  right_walk = &right;  
  left_count = right_count = 0;  
  //取第一個節點作為比較的基準,小于基準的在左面的子鏈表中,  
  //大于基準的在右邊的子鏈表中  
  for (old = (*head)->next; old != end; old = old->next)
  {  
   if (old->data < pivot->data)
   {      //小于基準,加入到左面的子鏈表,繼續比較  
    ++left_count;  
    *left_walk = old;            //把該節點加入到左邊的鏈表中,  
    left_walk = &(old->next);  
   }
   else
   {                         //大于基準,加入到右邊的子鏈表,繼續比較  
    ++right_count;  
    *right_walk = old;             
    right_walk = &(old->next);  
   }  
  }  
  //合并鏈表  
  *right_walk = end;       //結束右鏈表  
  *left_walk = pivot;      //把基準置于正確的位置上  
  pivot->next = right;     //把鏈表合并  
  //對較小的子鏈表進行快排序,較大的子鏈表進行迭代排序。  
  if(left_walk > right_walk)
  {
   QListSort(&(pivot->next), end);  
   end = pivot;  
   count = left_count;  
  }
  else
  {  
   QListSort(head, pivot);  
   head = &(pivot->next);  
   count = right_count;  
  }  
 }
 while (count > 1);   
}

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩高清中文字幕| 九九热这里只有在线精品视| 色综合久久天天综线观看| 91久久久久久久久| 精品亚洲一区二区三区在线观看| 久久久久九九九九| 亚洲毛片在线看| 精品成人乱色一区二区| 久久伊人免费视频| 久久免费成人精品视频| 成人夜晚看av| 欧洲亚洲妇女av| 国产精品久久中文| 亚洲高清色综合| 国产精品视频久| 国产欧美在线视频| 这里只有精品在线观看| 日韩女优在线播放| 久久精品成人欧美大片| 狠狠躁夜夜躁人人爽天天天天97| 2018国产精品视频| 色综合色综合久久综合频道88| 久久精品国产99国产精品澳门| 曰本色欧美视频在线| 色一区av在线| 欧美国产亚洲精品久久久8v| 成人福利网站在线观看11| 欧美一区二区.| 国产一区二区免费| 国产精品偷伦免费视频观看的| 日韩精品视频在线播放| 麻豆乱码国产一区二区三区| 中文日韩在线观看| 国产成人精品优优av| 亚洲精品有码在线| 在线丨暗呦小u女国产精品| 色综合色综合久久综合频道88| 亚洲欧洲国产一区| 成人福利网站在线观看| 日韩av资源在线播放| 日韩av有码在线| 日韩欧美第一页| 国产精品爱啪在线线免费观看| 国产精品igao视频| 欧美性猛交xxxx偷拍洗澡| 日本久久久久久久久久久| 日韩视频一区在线| 色综合久久久888| 久久久爽爽爽美女图片| 亚洲欧美一区二区三区久久| 色久欧美在线视频观看| 亚洲a区在线视频| 成人精品视频久久久久| 尤物tv国产一区| 夜夜躁日日躁狠狠久久88av| 欧美日韩午夜视频在线观看| 国产成人在线一区| 色噜噜狠狠色综合网图区| 久久精品国产91精品亚洲| 欧美极品在线视频| 欧美激情综合亚洲一二区| 亚洲欧美日韩区| 一区二区中文字幕| 亚洲视频日韩精品| 欧美极品xxxx| 亚洲国产精品久久久久秋霞蜜臀| 久久久久久国产| 国产免费观看久久黄| 欧美在线观看网址综合| 日韩av资源在线播放| 欧美成人小视频| 国产精品一区二区av影院萌芽| 成人激情视频小说免费下载| 亚洲日本成人网| 日韩免费av一区二区| 福利视频导航一区| 国产精品高清在线观看| 亚洲男子天堂网| 国产中文日韩欧美| 久久全球大尺度高清视频| 青青草一区二区| 亚洲天堂男人天堂| 欧美国产日韩免费| 亚洲精品国产成人| 国产精品v片在线观看不卡| 日韩av在线免费观看| 欧美精品18videos性欧美| 欧美天天综合色影久久精品| 国产精品一区久久久| 亚洲欧洲偷拍精品| 97香蕉久久超级碰碰高清版| 国产亚洲综合久久| 久久久久成人精品| 在线播放日韩精品| 日韩国产欧美精品一区二区三区| 97超碰国产精品女人人人爽| 亚洲国产精品va在看黑人| 亚洲精品v欧美精品v日韩精品| 欧美高跟鞋交xxxxxhd| 日韩a**中文字幕| 亚洲二区在线播放视频| 69国产精品成人在线播放| 欧美精品久久久久久久免费观看| 国产精品久久久久久av福利| 热久久免费国产视频| 国产精品自拍小视频| 色噜噜国产精品视频一区二区| 欧美一级片一区| 久久在线视频在线| 久久夜色精品国产亚洲aⅴ| 亚洲va男人天堂| 色yeye香蕉凹凸一区二区av| 日韩视频第一页| 欧美激情一二三| 午夜欧美不卡精品aaaaa| 久久国产精品久久国产精品| 91久久久国产精品| 精品伊人久久97| 亚洲午夜女主播在线直播| 亚洲精品www久久久| 欧美日韩国产麻豆| 日本精品久久久久久久| 亚洲欧洲高清在线| 国产精品精品视频| 日本精品视频在线观看| 久久在精品线影院精品国产| 久久久精品久久久| www.日韩免费| 欧美激情第一页xxx| 亚洲国产美女久久久久| 日韩大陆欧美高清视频区| 日韩精品极品在线观看播放免费视频| 欧美激情欧美狂野欧美精品| 久久99久国产精品黄毛片入口| 欧美日韩国产成人| 欧美电影免费看| 久久视频这里只有精品| 久久艹在线视频| 精品国产鲁一鲁一区二区张丽| 国产黑人绿帽在线第一区| 亚洲激情视频网| 在线看欧美日韩| 96sao精品视频在线观看| www国产精品视频| 欧美日韩色婷婷| 欧美二区乱c黑人| 日本精品一区二区三区在线| 欧美第一淫aaasss性| 日本电影亚洲天堂| 日韩**中文字幕毛片| 69国产精品成人在线播放| 亚洲va久久久噜噜噜| 国产精品视频网| 在线播放国产精品| 亚洲综合中文字幕在线| 欧美精品www| 成人激情视频网| 96精品视频在线| 欧美日韩在线第一页| 国产精品久久久久久久久久东京| 成人看片人aa| 亚洲国产天堂久久综合网| 91精品国产91久久久久久| 国产精品扒开腿爽爽爽视频|