单链表上的快排

  正常数组上的快排很常考,可以参考 https://blog.csdn.net/Bob__yuan/article/details/98782859 以及求数组第K大元素时使用的快排:https://blog.csdn.net/Bob__yuan/article/details/100145469
  在链表上进行排序一般用归并,可以参考 https://blog.csdn.net/Bob__yuan/article/details/100621973

  本篇文章记录在单链表上的快排。这个在日常编程中,一般情况不会用,但是网上有面经说考到了,所以记录一下。
  由于链表是不能随机存取的,只能顺序遍历,所以不能按照下标的方式进行遍历,但是思想和正常数组上的快排是一模一样的。核心思想就是用两个指针 slow 和 fast,每次保证 slow 一定指向 <= pivot 的节点,slow 的下一个节点值一定 > pivot 或者 slow == fast

算法步骤如下:

  1、每轮迭代设 slow 指向第一个节点(第一个节点为 pivot),fast 指向 slow 的下一个节点;
  2、当 fast 没有到达链表末尾时,若 fast 指向的值 >= pivot,更新 fast 指向 fast 的下一个元素;若 < pivot,则将更新 slow 指向 slow 的下一个元素,并将 slow 与 fast 指向的值交换,更新 fast 指向 fast 的下一个元素。也就是 fast 每次一定是往前走一个位置的。
  3、循环执行步骤2直至 fast 到达链表尾部;交换链表头元素与 slow 指向元素值。
  4、以 slow 为分割点(后半部分链表的 head)将链表分为两部分,两个序列递归调用上述步骤排序完成。

#include <iostream>
using namespace std;

struct ListNode {
	int val;
	ListNode *next;
	ListNode(int x) : val(x), next(nullptr) {}
};

int rnd = 1;	// round用于输出每一轮快排结果
ListNode* h;

ListNode* partition(ListNode* begin, ListNode* end) {
	if (!begin) return nullptr;
	ListNode* slow = begin, *fast = begin->next;
	const int pivot = begin->val;
	while (fast != end) {
		if (fast->val < pivot) {
			slow = slow->next;
			swap(slow->val, fast->val);
		}
		fast = fast->next;
	}
	swap(begin->val, slow->val);
	return slow;
}

void quicksort(ListNode* begin, ListNode* end) {
	if (begin != end) {
		ListNode* mid = partition(begin, end);
		/// 输出每一轮快排结果
		ListNode *ite = h;
		printf("第 %d 轮快排结果为:", rnd++);
		while (ite) {
			cout << ite->val << ' ';
			ite = ite->next;
		}
		cout << endl;
		quicksort(begin, mid);
		quicksort(mid->next, end);
	}
}

int main() {
	// 6 2 1 3 5 4
	ListNode *head = new ListNode(6);
	h = head;
	head->next = new ListNode(2);
	head = head->next;
	head->next = new ListNode(1);
	head = head->next;
	head->next = new ListNode(3);
	head = head->next;
	head->next = new ListNode(5);
	head = head->next;
	head->next = new ListNode(4);

	quicksort(h, nullptr);	// 左闭右开区间!!

	while (h) {
		cout << h->val << " ";
		h = h->next;
	}
}

  6 2 1 3 5 4 结果如下:

第 1 轮快排结果为:4 2 1 3 5 6
第 2 轮快排结果为:3 2 1 4 5 6
第 3 轮快排结果为:1 2 3 4 5 6
第 4 轮快排结果为:1 2 3 4 5 6
第 5 轮快排结果为:1 2 3 4 5 6
第 6 轮快排结果为:1 2 3 4 5 6
1 2 3 4 5 6

  上边代码是有调试测试的,实际核心代码就是:

ListNode* partition(ListNode* begin, ListNode* end) {
	if (!begin) return nullptr;
	ListNode* slow = begin, *fast = begin->next;
	const int pivot = begin->val;
	while (fast != end) {
		if (fast->val < pivot) {
			slow = slow->next;
			swap(slow->val, fast->val);
		}
		fast = fast->next;
	}
	swap(begin->val, slow->val);
	return slow;
}

void quicksort(ListNode* begin, ListNode* end) {
	if (begin != end) {
		ListNode* mid = partition(begin, end);
		quicksort(begin, mid);
		quicksort(mid->next, end);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章