插入排序演算法之直接插入排序和希爾排序

2021-08-07 06:56:13 字數 4296 閱讀 9862

有乙個已經有序的資料序列,要求在這個已經排好的資料序列中插入乙個數,但要求插入後此資料序列仍然有序,這個時候就要用到一種新的排序方法——插入排序法,插入排序的基本操作就是將乙個資料插入到已經排好序的有序資料中,從而得到乙個新的、個數加一的有序資料。

直接插入排序的排序思路是:每次將乙個待排序的元素與已排序的元素進行逐一比較,直到找到合適的位置按大小插入。

例子:有序列:

開始時,有序序列只有乙個元素就是第乙個元素(紅色),後面的無序序列(綠色)。接下來,取無序序列中的第乙個元素3,把它放到有序系列的合適位置。方法是,從有序序列的最後面向前,依次和3比較,如果比3大,就向後移動乙個位置,直到找到比3小的元素,然後把3插到後面(由於後面的元素已經依次移動,所以該位置已經空出),或者有序序列中沒有比3小的元素,則將3放在有序序列的第乙個位置(由於移動,該位置已經空出)。最後結果為:

同樣,取無序佇列中的第乙個元素,也就是6,然後,從有序序列的後面依次向前比較,首先是8,大於6,則向後移動(注意,8後移則會佔據6的位置,所以要提前將6存乙份)。接著比較3和6,3比6小,所以將6插在3的後面(也就是原來8的位置,8已經後移,該位置已空)。所以結果就是: 

繼續下去,直到安排好最後乙個元素。 

**:**也很簡單,主要的就是比較和後移,但要注意,要將待排序的元素多存乙份,因為後移時,會佔據該元素的位置。

#include void insert_sort(int value,int

n)

//否則退出迴圈

break

; }

//退出迴圈時,說明value[i]大於value[j],這時,應該將value[i]放在value[j]的後面(後面乙個位置已經移空)

//還有一種情況是前面所有元素都比value[i]大

value[j + 1] =temp;}}

}int

main()

; insert_sort(value,

10);

printf(

"排序後的結果為:\n");

int i = 0

;

for(;i < 10;i++)

printf(

"%d

",value[i]);

printf("\n

");return0;

}

時間複雜度

只是定性的乙個分析:從**中可以看出,演算法的核心就是比較和移動,如果序列本身是有序的,那麼只需要n次比較,不需要移動,所以此時的時間複雜度為o(n)。如果序列是倒序的,則排第n個元素時,需要與前n-1個元素進行比較,前n-1個元素也都要後移。這樣n從1取到n就是,比較和移動的次數都是0+(2-1)+(3-1)+..+(n-1)結果就是n*(n-1)/2,所以是o(n2)級別。書上說,直接插入排序的平均時間複雜度也是o(n2)級別。

是否是穩定的

是的。(稍微想一下就知道)

希爾排序是希爾(donald shell)於2023年提出的一種排序演算法。希爾排序也是一種插入排序,它是簡單插入排序經過改進之後的乙個更高效的版本,也稱為縮小增量排序,同時該演算法是衝破o(n2)的第一批演算法之一。

希爾排序演算法的時間複雜度和步長的選取有關,平均時間複雜度為o(nlog2n),最壞為o(n2),最好為o(n).

直接插入排序更適合於原始記錄基本有序的集合。這是因為如果記錄基本有序,那麼直接插入排序時移動的次數就會很少。而希爾排序正式利用了直接排序的這乙個特點,希爾排序將資料按一定的步長進行分組,是的記錄很快就會達到整體基本有序。

例子:有序列:

首先選擇乙個步長,前面說過不同的初始步長會導致不同的時間複雜度,書上說,希爾排序的步長選擇是乙個數學難題,所以我們不要糾結。最常用的初始步長就是length/2。在這個例子中,length=9,所以初始步長step=4。然後我們將原序列分成四組(記住,步長是多少就分成多少組!!!!),分組的原則是,同一組中的元素中,每兩個元素之間的下標的差為步長step。分組結果如下(相同顏色為一組)

然後,分別對每一組按照直接插入排序的方法進行排序(注意,此時每組中相鄰的兩個元素之間的下標差是步長step,而不是1)結果為:

然後改變步長:step=step/2,所以這一輪的步長為2,然後將陣列分成兩組(再次說明,步長是多少,就分多少組)。如下(相同顏色為一組):

然後按照直接插入進行排序

然後,繼續改變步長,step=step/2,所以這一輪的步長為1,此時素組就分成一組了:

然後,按照直接插入排序進行排序,

接下來改變步長,step=step/2,步長為0,結束。

寫**:

通過上面的例子我們可以看到,實際上對分成的每乙個組,進行的操作還是直接插入排序,只不過處理時,要考慮相鄰兩個元素之間的下標差不在是1,而是step。所以,我們首先要對上面直接插入排序的函式insert_sort()進行必要的修改,加入兩個引數:首元素的下標(以確定是對哪一組資料進行直接排序)和步長。如下:

/*

* * 修改直接插入排序的函式

* 加上了兩個引數:start_index表示每組的第乙個元素的下標

* step表示步長

* */

void insert_sort(int value,int n,int start_index,int

step)

//否則退出迴圈

break

; }

//退出迴圈時,說明value[i]大於value[j],這時,應該將value[i]放在value[j]的後面(後面乙個位置已經移空)

//還有一種情況是前面所有元素都比value[i]大

value[j + step] =temp;}}

}

最後主函式中,主要任務就是分組,然後對每組資料都呼叫insert_sort()函式,還是再次強調:step是多少就分多少組!!!

完整**

#include /*

* * 修改直接插入排序的函式

* 加上了兩個引數:start_index表示每組的第乙個元素的下標

* step表示步長

* */

void insert_sort(int value,int n,int start_index,int

step)

//否則退出迴圈

break

; }

//退出迴圈時,說明value[i]大於value[j],這時,應該將value[i]放在value[j]的後面(後面乙個位置已經移空)

//還有一種情況是前面所有元素都比value[i]大

value[j + step] =temp;}}

}int

main()

;

int len = 9

;

int step =len;

step /= 2

;

while(step != 0

)

step /= 2

; }

printf(

"排序後的結果為:\n");

int i = 0

;

for(;i < len;i++)

printf(

"%d

",value[i]);

printf("\n

");return0;

}

插入排序之直接插入排序

插入排序概述 有乙個已經有序的資料序列,要求在這個已經排好的資料序列中插入乙個數,但要求插入後此資料序列仍然有序,這個時候就要用到一種新的排序方法 插入排序法,插入排序的基本操作就是將乙個資料插入到已經排好序的有序資料中,從而得到乙個新的 個數加一的有序資料,演算法適用於少量資料的排序,時間複雜度為...

插入排序之直接插入排序

依次將每個記錄 無序表 插入到乙個已排好序的有序表中,得到乙個新的,記錄增加1的有序表 向撲克牌中插入新牌,圖書館整理圖書 有n個數,將第乙個數看做乙個有序表,從第二個開始從後向前比較,第一趟比較前兩個數,然後把第二個數按大小插入到有序表中 第二趟把第三個資料與前兩個數從後向前掃瞄,把第三個數按大小...

插入排序之直接插入排序

packagesort.algorithm publicclassdirectinsertsort inttemp,j for int i 1 i data.length i data j 1 temp 輸出排序好的資料 for int k 0 k data.length k 直接插入排序,一般對於...