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