單鏈表上的快排

  正常數組上的快排很常考,可以參考 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);
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章