希爾排序使用直接插入排序、二分插入排序的C++程式碼實現演算法

butterzhao發表於2020-11-19

我們先來複習下三種插入排序:
直接插入排序、折半插入排序、希爾排序、

縮小增量多遍插入排序——希爾排序
	不適合在鏈式儲存結構上實現
	如何比較一次移動一大步:將要排序的記錄序列分割成若干子序列,分別進行直接插入排序,待整個序列中的記錄基本有序時,再對全體記錄進行一次直接插入排序
	1.定義增量序列Dk:Dm>Dm-1>...D1=1
		比如第一次排序間隔為5,第二次排序間隔為3,第三次排序間隔為1
	2.對每個Dk進行Dk-間隔 插入排序(k=m,m-1,...,1)

	特點:
	1.一次移動,移動位置較大
	2.最後一次只需要少量移動
	3.增量序列必須是遞減的,且最後一個必須是1
	4.增量序列是互質的

1.直接插入排序

void insertsort(sqlist &L){
	int i, j;
	for ( i = 2; i <= L.length; ++i){//從第二個元素開始排序
		if ( L.r[i].key < L.r[i-1].key ){
			L.r[0] = L.r[i];//複製為哨兵

			for (j = i-1; L.r[0].key < L.r[j].key; --j){
				L.r[j+1] = L.r[j];
			}

			L.r[j+1] = L.r[0];
		}
	}
}

2.二分插入排序,在移動元素、插入元素方面與直接插入排序類似

二分插入排序

void insertsort(sqlist &L){
	for ( i = 2; i <= L.length; ++i ){//從第二個元素開始
		L.r[0]=L.r[i];//複製為哨兵

		low = 1;//虛擬碼
		high = i - 1;//虛擬碼
		while (low <= high){
			mid = (low + high) / 2;

			if ( L.r[0].key < L.r[mid].key )
				high = mid - 1;//若在左半區則將high移動到左邊
			else
				low = mid + 1;
		}//迴圈結束,high+1則為插入位置

		for ( j = i - 1; j >= high + 1; --j ){
			L.r[j+1] = L.r[j];//移動元素
		}
		L.r[j+1] = L.r[0];
	}
}



網上大多是使用直接插入排序的希爾排序演算法,我經過推導也寫出了二分插入的希爾排序演算法。


void shellsort(sqlist &L, int dlta[], int t){//Dk的值依次存在dlta[t]中
//按照增量序列dlta[0~t-1]對順序表L做希爾排序
	for (int k = 0; k < t; ++k )
		shellinsert(L, dlta[k]);//一次增量為dlta[k]的插入排序
}//shellsort

void shellinsert(sqlist &L, int dk){
	for ( i = dk + 1; i <= L.length; ++i){//從第二個開始與第一個開始比較,後面第三個與第二個比較,直到最後一個
		if ( r.[i].key < r.[i-dk].key ){//如果現在要插入的值小於上一個間隔的值}
			r[0] = r[i];//將現在要插入的值放到哨兵位置

			//法1——直接插入排序
			for ( j = i - dk; j > 0 && ( r.[0].key < r.[j].key ); j = j - dk ){//從後往前遍歷,直到找到比要插入的值大的最小值
				r[j+dk] = r[j];//所以比要插入的值大的元素後移
			}

			r[j+dk] = r[0];//插入元素


			//法2——二分插入排序
			int mid = 0;
			int low = i - dk;
			int high = i - 1;//需要在前面初始化

			while ( low <= high ){
				mid = ( low + high ) / 2;

				if ( L.r[0].key < L.r[mid].key )
					high = mid - dk;
				else
					low = mid + dk;//迴圈結束,high+dk則為插入位置
			}

			for ( j = i - 1; j >= high + dk; --j ){
				L.r[j+dk] = L.r[j];//移動元素
			}
			L.r[j+dk] = L.r[0];

		}
	}
}

不斷學習中,有錯誤希望大家指出,非常感謝

相關文章