排序 上 插排 希爾 堆排

2021-08-26 18:15:58 字數 3176 閱讀 2443

給每個新增的數在已有的數列中找到合適的位置,然後插入進去

例如乙個由小到大的排序:

原陣列為:4, 5, 2, 9, 3, 6, 8, 7

現在我們有了乙個陣列,我們可以假裝現在排過序的只有第乙個數,也就是說已有序列是第乙個數(i和j是下標,key代表當前要插入的數,j代表當前已經插入到了第幾個數,i是動態的用來與key作比較)

開始插入第二個數:從插入數的前乙個位置(當前插入arr[1],所以i從0開始)向前尋找第乙個不小於它的數,並進行交換,因為我們要把要插入的數插入到第乙個(從插入的位置向前數)小於等於它的數的後面,所以當我們遇到比key大的數的時候,就直接將這個數向後挪動即可。

第一次當走完0時,沒有發現比要插入的數小的,所以下標為j這個數插入完畢,進行查入下乙個數,即j=2,同時i從j的前乙個開始進行比較

我們發現i所在的數比要插入的數大,所以直接進行挪動,但是由於i沒有走完0的下標,所以還要繼續向前走(因為挪動後arr[j]的值就會變為5,但是我們現在時插入2,所一直要用2來進行比較,因此使用乙個key來記住我們當前要插入的數)。

當i走到陣列的盡頭,或者遇到小於等於它的資料時說明要插入的資料就可以插入到其下乙個下標的位置。

每個數的插入方式都是這樣,並且每插入乙個數,已經插入的數就已經有序,所以當插完整個陣列的時候,整個整個陣列的排序也就完成了。

因為我們使用的是當遇到的數小於等於要插入的數的進行插入,所以會相對穩定,如果只是小於的話,那麼碰到等於的數的時候,還會再進行向後挪動一次,這樣,時間不但增加,而且穩定性還會大大降低。

插入排序的時間複雜度:

空間複雜度:o(1)

以下是**:

//插入排序

void insertsort(int arr, int size)

else

}arr[i + 1] = key;//執行到此位置說明已經找到了要插入的位置}}

因為我們每次插入的時候,前面的數就已經有序,而我們使用的是遍歷式查詢比較,所以我們可以使用二分查詢來增加查詢的速度,當然使用二分查詢適合使用資料比較多的時候。

以下是**:

void binsertsort(int arr, int size)

else

}//要插入的位置已經找到

//先將此位置到已插入的數的位置的所有資料都向後移動

for (i = j-1; i > mid; i--)

//此時已經將mid後面的數全部向後挪動了一遍,所以只需要將key插入到當前的位置

arr[i] = key;}}

當待排列的數是逆序的時候,插入排序就需要o(n)的時間複雜度,為了減少壞情況時排序的時間複雜度,我們使用多次插入排序,前幾次排序時為了讓資料基本有序,然後最後一次插入排序的時間複雜度就基本為o(n)了。

希爾排序就是對插入排序的優化,可以認為希爾排序是多次插入排序

插入排序的時候,我們乙個乙個數挨著的插入,但是,希爾排序的前期是排序相隔相等的數,進行排序。例如資料:

從圖中我們可以知道,如果直接用來插入排序的話,排到後面的時候,時間複雜度會非常大所以我們首先將所有的白色進行排列的得到如下,因為我們是間隔三個資料進行排列的,所以速度是相當快的:

排完白色,再將其他兩個顏色也都分別排一下:

最後將所有的資料進行一次插入排序,而此時資料已經基本有序了,所以最後一次插入排序的時間複雜度基本為o(n)。

時間複雜度

一下是**:

void shellsort(int arr, int size)

else

}arr[i + gap] = key;

}g--;

}//此時輸出的好是:4 0 1 7 5 2 9 6 8,符合前期的期望,而再次進行插排時間複雜度就會大大減少

insertsort(arr, size);

}

上面的方式**看起來應該很清楚思路,但是總是覺得迴圈層數優點多,因為我們使用的是一層一層的排序,相對於上面的圖來說就是乙個顏色乙個顏色的進行排序,但是如果我們能直接從第乙個開始,每進入乙個顏色,都能進行一次該顏色的排序,那麼我們就不需要四一層迴圈了,我們可以通過簡單的修改**,來實現。

void shellsort(int arr, int size)

else

}arr[i + gap] = key;

}//此時輸出的好是:4 0 1 7 5 2 9 6 8,符合前期的期望,而再次進行插排時間複雜度就會大大減少

insertsort(arr, size);

}

因為堆的性質,頂部的數總是最大的或者最小的,所以,我們可以通過這個性質用堆來排序。

例如由大到小排序:

將所給資料建立乙個小堆,堆頂資料總是最小的。

選堆頂的資料和堆的最後乙個資料進行交換,然後進行向下調整,調整的時候不要調整已經交換的最大的資料,也就是不認為交換過後,這個最大的數還在堆裡。

繼續選出堆頂和最後乙個資料進行交換,此時最後乙個資料不包括之前交換過的資料,也就是說,每次和堆頂元素的交換,認為堆的元素個數就會少乙個(從堆尾少)。

直到堆的元素為0,算排序完畢,此時整個資料就是有序的了,因為每次交換都是把最大的像後面搬,並且是從後到前的順序是。

時間複雜度都是o(n*logn)

流程圖:

**:

//向下調整

void adjustdown(int arr, int parent, int size)

if (arr[parent] > arr[minchild])//父結點比最小的孩子大,就進行交換

else//符合堆了

}}//堆排序

void heapsort(int arr, int size)

//建好了

//讓堆頂的資料和堆中最後乙個資料進行交換,並且每交換一次,堆的大小減少乙個

for (int i=size-1; i>=0; i--)

}

排序總結 堆排

核心函式 adjustdown nums,i,n 將 i 節點下沉。void adjustdown int arr,int i,int n else break 通過自底向上對每個節點呼叫下沉函式adjustdown,就能實現建立最大堆 最小堆。因為葉節點不存在子節點,所以實際上i從 n 2 1開始...

排序演算法 堆排

堆排序 如果將堆結構中的資料看作是一顆完全二叉樹的各個節點,那麼堆的性質就是滿足如下性質的完全二叉樹 樹中任意非葉子節點的關鍵碼均不大於或不小於其左右孩子節點的關鍵碼。利用堆的有序性及其運算,可以容易的實現選擇排序的方法稱為堆排序。假設欲對含有n個物件的序列v 0 v 1 v n 1 進行堆排序,演...

排序總結 快排 歸併 堆排

1.煞筆快排 假設我們對陣列進行快速排序。首先在這個序列中找乙個數作為基準數,為了方便可以取第乙個數。遍歷陣列,將小於基準數的放置於基準數左邊,大於基準數的放置於基準數右邊。此時得到類似於這種排序的陣列。在初始狀態下7是第乙個位置,現在需要把7挪到中間的某個位置k,也即k位置是兩邊數的分界點。那如何...