演算法筆記 左神初級(2)快速排序 堆排序

2021-10-03 06:10:43 字數 4277 閱讀 5488

;}返回的是等於基準值的數字在陣列中的位置。

public

static

void

quicksort

(int

arr)

quicksort

(arr,

0, arr.length -1)

;}public

static

void

quicksort

(int

arr,

int l,

int r)

}public

static

int[

]partition

(int

arr,

int l,

int r)

else

if(arr[l]

> arr[r]

)else

}swap

(arr, more, r)

;return

newint

;}public

static

void

swap

(int

arr,

int i,

int j)

這是改進後的經典快排。可以看到partition函式會返回除基準值以外的數,而對基準值做了保留(這裡基準值指的是若干個相等的數!) 而經典快排,一次只搞定乙個數,也就是把初始的右側數作為基準放中間,小於等於放左邊,大於放右邊。這樣會導致左邊會包含等於基準值的若干個數。雖然複雜度相同,但常數時間會有差距。可以看見快排的核心函式是partiton函式,該函式的作用是把輸入陣列的右側資料用來做基準值,對資料進行快排,返回基準值的左邊部分(比基準值小)和右邊部分(比基準值大),再對左右部分進行partition。巢狀,最終對陣列完成排序。

經典快排的問題是他的效率會和資料狀況有關係,

參考master公式

具體原因是經典快排可能導致子區域劃分極不平均。

最好的情況複雜度為t(n)=2t(n/2)+o(n),否則複雜度較高。隨機快排和上面的經典快排**基本相同,唯一區別如下。

public

static

void

quicksort

(int

arr,

int l,

int r)

}

期望複雜度:o(n*logn),額外空間複雜度為o(logn)

這個額外空間複雜度的**是記錄的斷點位置,能被二分多少次,就需要存多少個。這是長期期望的概率,否則最差的情況額外複雜度為o(n)。

堆的結構就是一棵完全二叉樹;

完全二叉樹就是從樹的每層從左往右依次補全

完全二叉樹是由滿二叉樹而引出來的,若設二叉樹的深度為h,除第 h 層外,其它各層 (1~h-1) 的結點數都達到最大個數(即1~h-1層為乙個滿二叉樹),第 h 層所有的結點都連續集中在最左邊,這就是完全二叉樹。

堆一般都是用完全二叉樹來實現的。

左孩子: 2i+1; 右孩子:2i+2

父節點:(i-1)/2

大根堆:任何一顆子樹的最大值都是這個子樹的頭部

小根堆:任何一顆子樹的最小值都是這個子樹的頭部**如下:(加入乙個新節點往上調整的函式——heapinsert)

public

static

void

heapinsert

(int

arr,

int index)

}

上述過程中,arr是待排序的陣列,i(index)之前已經排好了大根堆,i指的是排好的大根堆中的下個數的索引。

如果 i 索引的數大於父節點,交換其和父節點的位置,再將新的父節點與它的父節點比較,迴圈

如果 i 索引的數不大於父節點,i++

建立乙個大根堆的時間複雜度

注意,乙個新節點 i 加入進來,最多比較的次數其實就是高度,也即是log(i-1)

所以建立乙個大根堆時間複雜度

log1+log2+log3+……+log(n-1) = o(n)

heapify函式

heapsize是指這個堆的大小(最大不超過陣列長度)

public

static

void

heapify

(int

arr,

int index,

int heapsize)

swap

(arr, largest, index)

;//否則往下沉

index = largest;

left = index *2+

1;}}

建立大根堆的過程使用的函式為heapinsert,

當大根堆裡的數變化後,維持大根堆結構函式為heapify,

堆資料可以增加也可以減少,堆資料增加可以使用heapinsert,

堆資料減少時將根節點彈出,最後節點放到根節點,再進行heapify

堆在系統中一般稱呼叫優先順序佇列,調整代價較小,只需要承擔logn的複雜度就可以完成,非常重要

乙個數列不斷增加,需要隨時求所有數的中位數,可以使用堆進行運算(分成大根堆和小根堆)

演算法流程:

1.首先建立兩個堆,乙個大根堆,乙個小根堆 (大根堆裡裝較小的數,小根堆裡裝大的數)

2.將第乙個資料防入大根堆

3.將下乙個資料跟大根堆中的資料進行比較,如果資料小於大根堆中的根,則放入大根堆中,否則裝入小根堆中。

4.如果大根堆和小根堆中的數目相差2,則將資料較多的堆的父節點彈出,放入資料較少的資料堆中當父節點。彈出根節點的堆,將堆底的數放到堆頂,然後執行響應的heapify操作,同時heapsize減一。接收節點的堆採用heapinsert操作。 回到步驟3 。

中位數的資料只會從大根堆和小根堆的父節點中選出,隨時進入資料,則可以隨時調整,複雜度較低。

1、全部形成大根堆

2、堆頂跟最後數交換

3、heapsize減一(最大的數就被留到了最後)

4、對根節點進行heapify操作,重新生成大根堆

5、回到步驟2,直到排完。

**如下:

public

class

code_03_heapsort

for(

int i =

0; i < arr.length; i++

)int size = arr.length;

swap

(arr,0,

--size)

;while

(size >0)

}public

static

void

heapinsert

(int

arr,

int index)

}public

static

void

heapify

(int

arr,

int index,

int heapsize)

swap

(arr, largest, index)

; index = largest;

left = index *2+

1;}}

public

static

void

swap

(int

arr,

int i,

int j)

左神演算法筆記(二) 快速排序,堆

08荷蘭國旗問題 將小於大於區域進行劃分,當數值小於則將資料放到左邊,l 1,當資料大於則將資料放到右邊r,同時將r 1.由於荷蘭問題較為簡單,因此在這裡不再編寫 public static void quicksort int arr quicksort arr,0,arr.length 1 pu...

2 排序演算法 快速排序

問題描述 利用快速排序演算法對下列例項排序,在演算法執行過程中,寫出陣列 a第一次排序後被分割的過程。a 65,70,75,80,85,55,50,2 解題思想 在快速排序中,記錄的比較和交換是從兩端向中間進行的,關鍵字較大的記錄一次就能交換到後面的單元,總的比較和移動次數較少。對於輸入的陣列a p...

演算法筆記2 排序

1.選擇排序 首先,找到陣列中最小的那個元素,其次,將他和陣列第乙個元素交換位置,再次,在剩下的元素中找到最小的元素,將他和陣列的第二個元素交換位置。如此反覆,直到將整個陣列排序。不斷的選擇剩餘元素的最小值 2.插入排序 對部分有序陣列很有效 為了給要插入的元素騰出空間,我們需要將其餘所有元素在插入...