歸併排序,快速排序,堆排序實現及複雜度分析

2022-09-11 13:39:24 字數 4166 閱讀 6376

排序中比較複雜的有歸併排序,快速排序,堆排序三大演算法了,三個演算法的時間複雜度都是o(n * logn),三個演算法的思想我就簡單的展開詳述以下。

歸併排序的核心思想是鍊錶中的經典題目:合併兩個有序鍊錶

劍指offer:合併兩個排序的鍊錶

leetcode p21: merge two sorted lists

採用分治的思想,將整個陣列分為兩個部分,先對左邊的陣列進行歸併排序,再對右邊的陣列進行歸併排序,最後兩者進行merge

下面的函式就是歸併排序的歸併部分,將兩個已經有序的陣列歸併。

public class mergesort implements sort

public void mergesort(int arr, int l, int r) 

public void merge(int arr, int l, int mid, int r)  else 

}while (left <= mid) 

while (right <= r) 

for (int i = 0; i < newarr.length; i++) 

}}

堆排序首先就要利用堆這個資料結構。首先先將整個陣列結構調整成堆。

heapinset函式插入某個數字,並且將插入的部分進行調整。對於乙個陣列,從位置0開始插入,並且邊插入邊進行調整。

public class heapsort implements sort

int heapsize = arr.length;

swap(arr, 0, --heapsize);

while (heapsize > 0) 

}public void heapinsert(int arr, int index) 

}public void heapify(intarr, int index, int heapsize) 

swap(arr, index, maxindex);

index = maxindex;

left = maxindex * 2 + 1;}}

public void swap(int arr, int i, int j) 

}

這樣處理完之後,陣列就成為了乙個最大堆。要將陣列調整為有序的,要經歷以下幾步:

陣列的第乙個數是最大堆的頂,是最大的數,每次將第乙個數和最大堆的最後乙個數交換。這樣後面部分就排好序了

交換完之後,最大堆的結構就會被破壞了,所以需要調整最大堆。

//交換到最後乙個位置

swap(arr, 0, --heapsize);

while (heapsize > 0)

調整位置

public void heapify(intarr, int index, int heapsize) 

swap(arr, index, maxindex);

index = maxindex;

left = maxindex * 2 + 1;

}}

快速排序的核心思想思想是選乙個數,不管是隨機的還是固定的,每一步將大於這個數的數字放在陣列的右邊,小於的所有數字放在左邊,聽起來是不是很熟悉,這就是經典題目荷蘭國旗的思想啦。

leetcode p75: sort colors

public class quicksort implements sort

public void quicksort(int arr, int l, int r) 

public int partition(int arr, int l, int r) ;

int num = arr[r];

int left = l - 1;

int right = r;

int cur = l;

while (cur < right)  else if (arr[cur] > num)  else 

}swap(arr, right++, r);

mids[0] = left;

mids[1] = right;

return mids;

}public void swap(int arr, int i, int j) 

public static void main(string args) ;

quicksort q = new quicksort();

q.sort(arr);

}}

master公式是為了評估遞迴函式的複雜度而誕生的。

t(n) = a* t(n / 2) + o(n^d)

log(b,a) > d時,時間複雜度是o(n ^ log(b,a))

log(b,a) = d時,時間複雜度是o(n ^ d + logn)

log(b,a) < d時,時間複雜度是o(n^d)

使用master公式計算三個排序的時間複雜度

merge-sort的核心**如下:

public void mergesort(int arr, int l, int r)
時間複雜度估算:

part 1部分將問題分為兩個部分,所以mastera=2,b=2

part 2部分是有序鍊錶的合併,時間複雜度是:o(n),所以d=1

所以套用master公式中的第二條,時間複雜度是o(n*logn)

merge-sort的核心**如下:

public void sort(int arr) 

int heapsize = arr.length;

(2)part2

swap(arr, 0, --heapsize);

while (heapsize > 0) 

}

時間複雜度估算:

最大堆的插入後調整的時間複雜度是o(logn)part 1部分是插入n個元素,時間複雜度是log1+log2+log3+log4+...+logn = n,所以part 1的時間複雜度是o(n)

part 2部分中heapify的時間複雜度是lognheapify就是堆的調整,所以part 2部分的時間複雜度是o(n * logn)

加起來就是o(n)+o(n*logn),取最大項即為o(n*logn)

quick-sort的核心**如下:

public void quicksort(int arr, int l, int r)
時間複雜度估算:

part 1中的partition思想是荷蘭國旗問題,時間複雜度是o(n)

part 2和歸併排序一樣,也是將問題分為了兩個部分,所以a=2,b=2

所以快速排序的時間複雜度是o(n*logn)

除了歸併排序中,需要提前分配o(n)的空間,作為merge過程中的快取。堆排序和快速排序全部都是in-place修改的,所以不需要分配額外空間。

其實在在歸併排序和堆排序過程中,因為函式遞迴,函式占用的棧位址也算空間複雜度,但是為什麼沒有算進去呢?個人認為是因為在一些高手的眼中,遞迴函式是可以改成迴圈,所以這就不用考慮這些額外空間了。

快速排序 堆排序 歸併排序

快速排序 includeusing namespace std int a 8 int sz sizeof a sizeof int int partition int a,int p,int r int main const int sz sizeof a sizeof int 堆化 保持最大堆的...

快速排序,歸併排序,堆排序

l r 1在奇數長度陣列的中間,偶數長度陣列的左半邊最後乙個,極限情況下陣列只有兩個數,i遇到第乙個數就會停下,此時模擬i,j下標的數有無交換的情況,會發現j在停下來時都位於第乙個數的位置,因此用j,j 1才不會越界 l r 1 1在奇數長度陣列的中間往右第乙個,偶數長度陣列的右半邊第乙個,極限情況...

關於快速排序,歸併排序,堆排序

1 快速排序 quicksort 快速排序是乙個就地排序,分而治之,大規模遞迴的演算法。從本質上來說,它是歸併排序的就地版本。快速排序可以由下面四步組成。1 如果不多於1個資料,直接返回。2 一般選擇序列最左邊的值作為支點資料。3 將序列分成2部分,一部分都大於支點資料,另外一部分都小於支點資料。4...