单链表快速排序

Posted 数学算法部落

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单链表快速排序相关的知识,希望对你有一定的参考价值。

假设对一组序列进行升序快速排序.


对于数组进行快速排序的基本思想:

对于每一轮迭代, 选定一个目标元素key(通常选第一个)用来做partition, 定义两个指针left、right分别指向数组的头和尾, left指针从左往右移动, 遇到比key大的值暂停, right指针从右往左移动, 遇到比key小的值暂停, 两个指针都停下时交换两个指针指向的元素, 然后两个指针继续移动, 直到两个指针相遇, 然后交换key与相遇处的元素, 这样通过一次迭代就把key对应的元素交换到了排序后它应该处于的正确位置, 然后以key当前所处的位置为临界点把序列分割成两部分, 对这两部分分别重复上面的操作, 以此类推.


在单链表上实现快速排序算法:

与数组很大的一个区别就是单链表不能从后往前进行遍历, 因此在做partition的时候, 两个指针都只能从前往后进行遍历.

具体思路是: 两个指针p、q都从头结点开始往后遍历, 开始的时候p指针指向头结点(key), q指针指向p的下一个结点, q指针从前往后查找比key值小的元素, 当q指针遇到比key值小的元素的时候, p前进一位, 交换p、q指向的元素, 如果q指针遇到的元素比key大, 则p指针不动, q指针继续向前查找, 直到q指针查找到链表末端. 显然q指针比p指针移动速度快, 这就保证了p指针前面的元素都比key小, 此时p指针指向的位置就是key对应的元素在排序后的正确位置, 也就是partition的位置, 因此交换key对应的元素与p指针当前指向的元素, 并以此位置作为partition的临界点.


Example:

假设对序列 [7, 9, 6, 1, 2, 3, 8, 5] 进行快速排序, 下面对比数组和单链表下一次迭代的过程.

约定: 符号"-->"表示下一步操作

数组:

初始状态: a=[7, 9, 6, 1, 2, 3, 8, 5], key = 7, left = 1, right = 7  (key对应的为实际值, left, right分别是两个指针所处的位置, 下面分别简写为l, r)

  1. a[l] = a[1] = 9 > key, a[r] = a[7] = 5 < key --> swap(a[l], a[r]) --> l++, r-- --> 得到序列 [7, 5, 6, 1, 2, 3, 8, 9], 此时l = 2, r = 6.

  2. a[l] = a[2] = 6 < key, a[r] = a[6] = 8 > key --> l++, r-- --> 序列不变, 此时 l = 3, r = 5.

  3. a[l] = a[3] = 1 < key, a[r] = a[5] = 3 < key --> l++, r不变 --> 序列不变, 此时 l = 4, r = 5.

  4. a[l] = a[4] = 2 < key, a[r] = a[5] = 3 < key --> l++, r不变 --> 序列不变, 此时 l = 5, r = 5.

  5. 由于l == r --> swap(a[5], a[0]) (l = 5, key对应a[0]) --> 得到序列 [3, 5, 6, 1, 2, 7, 8, 9] --> 该轮迭代结束, 以 位置5 为临界点做partition进行下一次迭代.


单链表:

初始状态: a=[7, 9, 6, 1, 2, 3, 8, 5], key = 7, p -> 0, q -> 1 (key对应实际值, p, q为两个指针, 对应的值为其所处位置, 如p -> 0表示p指向0位置, 头结点位置认为是0, 后面一次递增, 为了与上面数组的情况做区分, 用p->val、q->val分别表示p、q指向的元素的值)

  1. q->val = 9 > key --> q = q->next, 序列不变, 当前p -> 0, q -> 2

  2. q->val = 6 < key --> p = p->next --> swap(p->val, q->val) --> q = q->next --> 得到序列[7, 6, 9, 1, 2, 3, 8, 5], 此时p -> 1, q -> 3

  3. q->val = 1 < key --> p = p->next --> swap(p->val, q->val) --> q = q->next --> 得到序列[7, 6, 1, 9, 2, 3, 8, 5], 此时p -> 2, q -> 4

  4. q->val = 2 < key --> p = p->next --> swap(p->val, q->val) --> q = q->next --> 得到序列[7, 6, 1, 2, 9, 3, 8, 5], 此时p -> 3, q -> 5

  5. q->val = 3 < key --> p = p->next --> swap(p->val, q->val) --> q = q->next --> 得到序列[7, 6, 1, 2, 3, 9, 8, 5], 此时p -> 4, q -> 6

  6. q->val = 8 > key --> q = q->next, 序列不变, 此时p -> 4, q -> 7

  7. q->val = 5 < key --> p = p->next --> swap(p->val, q->val) --> q = q->next --> 得到序列[7, 6, 1, 2, 3, 5, 8, 9], 此时p -> 5, q -> null

  8. 由于q -> null(已经到达链表结尾) --> swap(p->val, head->val), 此处head->val对应key --> 得到序列[5, 6, 1, 2, 3, 7, 8, 9], 该轮迭代结束, 以当前p指向的位置(p -> 5)为临界点做partition进行下一轮迭代.




单链表快速排序C++实现:



以上是关于单链表快速排序的主要内容,如果未能解决你的问题,请参考以下文章

单链表快速排序

单链表快速排序

快速排序,归并排序,堆排序的数组和单链表实现

Java实现单链表的快速排序和归并排序

单链表快速排序

C-单链表-快速排序,冒泡排序