數據結構與算法-排序(七)希爾排序(Shell Sort)


摘要

看希爾排序需要先想象出一個二維的矩陣,在這個矩陣中,有多少列數據全看步長(一定的規則得到)。處理完之后,就再接着用另一個步長組成矩陣處理。直到步長全部使用完。

這里的巧妙之處就是沒有把序列先處理成二維數組,而是通過與步長配合,依舊在一維的序列中處理。

邏輯

希爾排序相當於把序列當作一個矩陣,逐列進行排序。當全部排序完成,整個序列就完全有序

矩陣的列數取決於步長序列

流程

  1. 創建步長序列
  2. 從最大步長開始,整列排序,直到排序完成

實現

創建步長序列,這里是有一個數組存放步長數據。步長是序列的長度減半直到步長為0 結束。這里必定會有步長是 1 的數據,所以不用擔心序列沒有完全排序完。

List<Integer> shellStepSequence() {
	List<Integer> stepSequence = new ArrayList<>();
	int step = array.length;
	while ((step >>= 1) > 0) {
		stepSequence.add(step);
	}
	return stepSequence;
}

按照步長序列遍歷,序列就會按照不同的步長去處理排序。然后通過不斷地縮小步長來使得序列逐漸成為一維的序列。

	List<Integer> stepSequence = shellStepSequence();
	for (Integer step : stepSequence) {
		sort(step);
	}

把每一列進行排序。數組中的索引是 col+row*step。這個地方就是巧妙的地方了,通過 col+row*step 來處理每一列中的元素比較排序處理。用這種方式就相當於把一個一維數組給拆分成每一行最多有 step 的元素的多列序列,即二維數組。

而這里的巧妙就是,給我們營造了一個二維序列的空間,實際的比較和交換邏輯還是在一維數組上進行,不用額外創造空間,這樣的邏輯,真的是牛。

/*
 * 分成 step 列進行排序
 */
void sort(int step) {
	// col: 第幾列
	for (int col = 0; col < step; col++) {
		// 對第 col 列進行排序
		// 對 [0, array.length) 進行插入排序
		for (int begin = col + step; begin < array.length; begin+=step) {
			int cur = begin;
			while (cur > col && cmp(cur, cur - step) < 0) {
				swap(cur, cur - step);
				cur -= step;
			}
		}
	}
}

時間和空間復雜度

  • 最好、平均時間復雜度:O(1)
  • 最壞時間復雜度:O(n^2)
  • 空間復雜度:O(1)
  • 屬於不穩定排序


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM