方法一:
單鏈表的快速排序和數組的快速排序在基本細想上是一致的,以從小到大來排序單鏈表爲例,都是選擇一個支點,然後把小於支點的元素放到左邊,把大於支點的元素放到右邊。但是,由於單鏈表不能像數組那樣隨機存儲,和數組的快排序相比較,還是有一些需要注意的細節:
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個子鏈表。爲了簡單起見,選擇鏈表的第一個節點作爲基準,然後進行比較,比基準大節點的放入左面的子鏈表,比基準大的放入右邊的子鏈表。在對待排序鏈表掃描一遍之後,左面子鏈表的節點值都小於基準的值,右邊子鏈表的值都大於基準的值,然後把基準插入到鏈表中,並作爲連接兩個子鏈表的橋樑。然後根據左右子鏈表中節點數,選擇較小的進行遞歸快速排序,而對數目較多的則進行迭代等排序,以提高性能。
- /**
- * 單鏈表的快排序
- * author :blue
- * data :2010-4-6
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- //鏈表節點
- struct node {
- int data;
- struct node *next;
- };
- //鏈表快排序函數
- void QListSort(struct node **head, struct node *head);
- //打印鏈表
- 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;
- struct node *p;
- int i = 0;
- /**
- * 初始化鏈表
- */
- head = (struct node*)malloc(sizeof(struct node));
- head->next = NULL;
- head->data = 0;
- srand((unsigned)time(NULL));
- for (i = 1; i < 11; ++i) {
- p = (struct node*)malloc(sizeof(struct node));
- p->data = rand() % 100 + 1;
- p->next = head->next;
- head->next = p;
- }
- print_list(head);
- printf("---------------------------------/n");
- QListSort(&head, NULL);
- print_list(head);
- 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);
- }