在算法思想上,對於單鏈表的快速排序和對於數組的快速排序基本一致,但是同時也存在很大的區別,導致的原因我們也很容易明白,那就是單鏈表不支持像數組那樣的方便的訪問下標,也就是說我們無法對其進行從末尾向前遍歷。所以我們將第一個鏈表第一個結點的值作為左軸,然后向右進行遍歷,設置一個small指針指向左軸的下一個元素,然后比較如果比左軸小的話,使small指針指向的數據與遍歷到的數據進行交換。最后將左軸元素與small指針指向的元素交換即可。之后就是遞歸。具體圖解如下:
下面附上代碼:
void quicksort(Linklist head, Linklist end){ if(head == NULL || head == end) //如果頭指針為空或者鏈表為空,直接返回 return ; int t; Linklist p = head -> next; //用來遍歷的指針 Linklist small = head; while( p != end){ if( p -> data < head -> data){ //對於小於軸的元素放在左邊 small = small -> next; t = small -> data; small -> data = p -> data; p -> data = t; } p = p -> next; } t = head -> data; //遍歷完后,對左軸元素與small指向的元素交換 head -> data = small -> data; small -> data = t; quicksort(head, small); //對左右進行遞歸 quicksort(small -> next, end); }
此外,對於鏈表,快排還有其他的思路。那就是將基准定下來后,遍歷鏈表,選擇比基准小的連成一個新的子表,選擇比基准大的連成一個新的子表,然后將基准插入,進而再對兩個子表進行遞歸快排
void Quicksort(Linklist *head, Linklist end){ Linklist right; Linklist *p1; Linklist *p2; Linklist flag; Linklist old; int num, left_num, right_num; if(*head == end) return ; do{ flag = *head; //基准元素 p1 = head; //比基准元素小的鏈表 p2 = &right; //比基准元素大的鏈表 left_num = right_num = 0; //記錄兩個鏈表長度的大小 for(old =(*head) -> next; old != end; old = old -> next){ //遍歷當前函數中的鏈表 if(old -> data < flag -> data){ //對於小於基准的元素,放在左鏈表中 left_num ++; *p1 = old; p1 = &(old -> next); } else{ ++right_num; //對於大於基准的元素,放在右鏈表中 *p2 = old; p2 = &(old -> next); } } *p2 = end; //封死右鏈表 *p1 = flag; //將基准插入在兩個鏈表之間 flag -> next = right; if(left_num > right_num){ //對長度更小的鏈表進行遞歸快排運算 Quicksort(&(flag -> next), end); end = flag; num = left_num; } else{ Quicksort(head, flag); head = &(flag -> next); num = right_num; } }while(num > 1); }
對於鏈表中的快速排序暫時說這么多,但是實際上快排是不適合單鏈表的,應用歸並排序效率更好