插入排序與歸併排序

2021-08-07 23:50:19 字數 2995 閱讀 1744

關於排序似乎從大一開始學習變成就開始在使用各種排序方法了,今天看了下有關於插入排序和歸併排序的內容,並且對應在leetcode 上面做了兩道測試題,因此就對插入排序和歸併排序做乙個簡單的小結吧,就當做是我的學習筆記,大佬請勿嘲笑!

關於插入排序主要的思想就是從左到右的遍歷乙個序列,有乙個標識來標記,保證左邊的序列有序,再往右遍歷的過程中將序列中的乙個元素插入到左邊的序列裡面,插入之後左邊的序列仍然保持有序,如果是乙個陣列的話那麼在遍歷插入之前會伴隨著數字的移動。

具體的來看乙個例子:題目很簡潔,只有一句話:sort a linked list using insertion sort. 對於這樣乙個題目,雖然要採用插入演算法的思路但是我在做的時候並沒有直接對鍊錶使用插入演算法,而是用乙個陣列將鍊錶中的內容複製下來,排序之後再放回到鍊錶中!以下是**:

/**

* definition for singly-linked list.

* struct listnode ;

*/struct listnode* insertionsortlist(struct listnode* head)

if (len > 1)

arr[j + 1] = key;}}

start = head;

j = 0;

while (start != null)

free(arr);

}return head;

}

這個演算法在最好的情況下的時間複雜度就是遍歷這個序列的時間複雜度o(n),這個時候這個序列是已經排好序的;最糟糕的情況下的時間複雜度的o(n^2),這個時候這個序列是按照相反的順序排列的,這裡就不再贅述對這個演算法正確性以及時間複雜度的分析,接下來以歸併排序為例來分析時間複雜度!

歸併排序遵循了分治模式,直觀上就是分解:分解帶排序的元素的序列成各具n/2個元素的兩個子串行;解決:使用歸併排序遞迴的排序兩個子串行;合併:合併兩個已排序的子串行以產生已排序的答案。

首先看看如何合併已排序的兩個陣列,為了避免在每乙個基本步驟都必須檢查陣列是否已經到了最末端,在兩個陣列的最末端都放置了哨兵——將兩個陣列的最末端的元素設定為最大,這樣就可以避免對陣列的檢查:

int* mergesort(int* arr, int p, int q, int r) 

else

if (left[i] > right[j])

}free(left);

free(right);

return arr;

}

下面使用迴圈不變式方法來證明這個演算法的正確性:

初始化:在迴圈的第一次迭代之前,有k=p,陣列arr[p, k - 1]為空,i, j 均為0,說明left[i]和right[j]都是各自所在陣列裡最小的元素,且這兩個元素均沒有被複製到arr陣列裡面;

保持:為了更好的理解迴圈不變式,首先假設left[i] <= right[j],這時left[i]是最小的沒有被複製到陣列裡的最小的元素,將left[i]複製到陣列裡面之後陣列arr[p…k]包含了k-p-1個最小的元素,然後p 和 i,均加1,為下一次迭代重新建立了迴圈不變式。

終止:迴圈終止的條件是k=r+1。這個時候陣列包含了兩個陣列的所有元素,且是有序的。

綜上所述,證明了上述演算法的正確性!

接下來考慮遞迴演算法:

int* merge(int* arr, int p, int r) 

return arr;

}

遞迴演算法將乙個陣列分成兩半,分別對這兩半進行排序之後,再將這兩個排好序的陣列組合成為乙個陣列。

接下來分析歸併演算法的時間複雜度:

每一次都將乙個節點劃分成為兩個,直到所有的節點都被劃分成為最小的單位為止,劃分的時候會產生log n + 1層,而對於每一層的劃分,總的代價都是cn(遍歷大陣列,產生每乙個小陣列),所以遞迴的總的代價就是cn(log n + 1) ,時間複雜度為 n(log n).

以下是本次在leetcode上面所做的題目:sort a linked list in o(n log n) time using constant space complexity.

根據上面的分析,程式如下所示:

/**

* definition for singly-linked list.

* struct listnode ;

*/struct listnode* sortlist(struct listnode* head)

else

if (left[i] > right[j])

}free(left);

free(right);

return arr;

}int* merge(int* arr, int p, int r)

return arr;

}int size = 0;

struct listnode* temp = head;

while (temp != null)

if (size > 1)

merge(arr1, 0, size - 1);

temp = head;

size = 0;

while (temp != null)

free(arr1);

}return head;

}

參考: 演算法導論 thomas h. cormen charles e. leiserson

ronald l. rivest clifford stein. 機械工業出版社!

插入排序 歸併排序

插入排序 define len 5 int a len void insertion sort void int i,j,k for j 1 j len j k a j i j 1 while i 0 a i k a i 1 a i i a i 1 k 歸併排序 int a 8 void merge...

插入排序 歸併排序

演算法導論初涉,第一講練習內容 include define n 6 int a n void init 初始化陣列 a i 1 k void output int a,int n void merge int low,int mid,int high while s mid b i a s whi...

插入排序 歸併排序

一直沒自己寫過 然後自己寫了下 其實我主要查的wikipedia 插入排序 歸併排序 先插排 插入排序 英語 insertion sort 是一種簡單直觀的 排序演算法 它的工作原理是通過構建有序序列,對於未排序資料,在已排序序列中從後向前掃瞄,找到相應位置並插入。插入排序 在實現上,通常採用in ...