堆排序是一種選擇排序,遍歷後選擇陣列中最大的值放到堆頂,可用陣列實現,最好和最壞和平均複雜度都為o(nlogn),不穩定。
堆就是一種完全二叉樹,排序特徵是堆頂元素大於子元素(不管子元素之間的排列);完全二叉樹的特徵是層序遍歷等於滿二叉樹的層序遍歷(也就是底層可以沒有右邊的子樹)
用陣列來描述堆的定義有大頂堆和小頂堆,若為大頂堆,則i的父節點為i/2,子節點為2i和2i+1
arr[i]arr[2i] && arr[i]>arr[2i+1]
但是放到陣列中父節點變成了2(i-1) 子節點為2i+1,2i+2
公升序使用大頂堆,就是先將待排序陣列構造成乙個大頂堆,此時堆頂為最大值,將它放到最後乙個(對應陣列中就是最後乙個值),就找到了最大值,然後將剩下的值再次排序可以找到第二大的值,將它放到堆底,如此反覆就可以將所有值排序
堆頂也就是陣列0位置,堆尾就是陣列的最後乙個位置
步驟1.構造大頂堆的時候就是從第乙個非葉節點(也就是倒數第二層,因為從這開始才有子節點i/2-1)開始調整(調整就是將此元素下沉到適合它的位置),然後一直迴圈到0也就是堆頂,這時所有元素都完成下沉。
2.此時已經構造好大頂堆,所以交換堆頂元素到堆底,下沉堆頂元素,迴圈繼續交換,下沉。此時迴圈的i就是未調整的長度可變的,每次都下沉堆頂元素0.
調整的操作是實質就是下沉,需要的是陣列,下沉元素位置,還有最大的陣列長度(也就是除去已經交換完的位置),目的是把arr[i]值下沉到它該去的位置。第一步就是儲存arr[i]為temp,進入for迴圈,從i的左子節點2i+1開始一直到length結束,進入之後首先找到它的兩個子節點中大的那乙個,如果此時大的那個子節點大於i,就把子節點值賦值給父節點(不是交換,而是把arr[i]值和i值都改變成是arr[j],j),然後接著迴圈,一直迴圈到結束或者時子節點值不再大於父節點。for迴圈執行完之後將temp放回到arr[i]處。
邊界條件一定注意
public
static
void
main
(string
argc)
;sort
(arr)
;for
(int i=
0;ipublic
static
void
sort
(int
arr)
for(
int i=arr.length-
1;i>
0;i--)}
public
static
void
sink
(int
arr,
int i,
int length)
if(arr[j]
>temp)
else
} arr[i]
=temp;
}public
static
void
swap
(int
arr,
int lo,
int hi)
歸併的操作就是把兩個以及排序好的佇列歸併merge到一起,兩個就是二路歸併。
時間複雜度為o(nlogn),最好為o(nlogn)最差為o(nlogn),穩定。
所以它的複雜度和堆排序一樣,但穩定,所以工程中物件的排序一般用歸併排序
過程很簡單,就是遞迴,然後歸併操作
歸併merge操作很重要,在歸併排序中需要的是建立乙個新陣列,然後遍歷舊陣列中的兩個部分,將值放到新陣列中,最後全部遍歷完成則將舊陣列的值放到新陣列中。
merge操作的應用有很多,比如說逆序對問題,比如說小和問題。
static
void
mergesorta
(int
a)public
static
void
mergesort
(int
arr,
int lo,
int hi)
int mid=lo+
((hi-lo)
>>1)
;mergesort
(arr,lo,mid)
;mergesort
(arr,mid+
1,hi)
;merge
(arr,lo,mid,hi);}
public
static
void
merge
(int
arr,
int lo,
int mid,
int hi)
else
}while
(p1<=mid)
while
(p2<=hi)
for(
int i=
0;i)}
快速排序利用的主要是partition操作和遞迴,每次都先將陣列分割成兩部分,小於a的放左邊,大於a的放右邊。然後遞迴分割這兩部分。
與歸併排序的區別是歸併是先遞迴,然後歸併排好序的兩部分。快排是先分割,然後遞迴分割兩部分。
平均複雜度為o(nlogn),最好o(n),最壞o(n2),不穩定,所以工程中排序基本資料型別用的就是快速排序。
比起普通的快速排序,改進的地方主要有借鑑了荷蘭國旗問題將partition分成了三部分,第二個改進的地方就是切分的時候是隨機乙個數來切分的。
partiton操作非常重要,主要思想就是通過遍歷把陣列分成前後兩部分或者是三部分,分成三部分需要兩個分界點,分成兩部分需要兩個分界點。
只需要乙個while操作遍歷即可完成分割。
public
static
void
main
(string
argc)
;sort
(arr)
;for
(int i=
0;ipublic
static
void
sort
(int
arr)
quicksort
(arr,
0,arr.length-1)
;}public
static
void
quicksort
(int
arr,
int lo,
int hi)
int[
] mid=
partition
(arr,lo,hi)
;quicksort
(arr,lo,mid[0]
-1);
quicksort
(arr,mid[1]
+1,hi);}
public
static
int[
]partition
(int
arr,
int lo,
int hi)
else
if(arr[cur]
>arr[hi]
)else
}swap
(arr,hi,more++);
return
newint
;}public
static
void
swap
(int
arr,
int lo,
int hi)
partition應用也非常多,就是在考慮分組成幾部分或者要得到某部分的時候非常有用。
1.比如說第乙個是返回超過陣列中一半長度的數字,這個可以根據它的特點知道排好序的中位數肯定是這個數字。所以可以利用partition將隨機乙個數字進行分割,分為前面小於它,後面大於它,中間等於它,如果返回發現中間位置不在等於它的範圍內,就縮小範圍來迴圈partition,直到發現這樣的數在中間了。再看這個數是否超過一半,超過則就是這個數,不超過則返回0。
2.返回陣列中第k大的數字,其實就是乙個partition,先隨機選乙個數字,左邊比它小右邊比它大,然後如果不在第k個接著partition,直到找到第k個數。
3.比如說找出陣列中的前k個數,這個也是要把陣列分成兩半,先以乙個數比如說第k個數partition,分好之後看它的左邊有幾個數,不管小於還是大於都迴圈partition直到分好之後下標為k
關於複雜排序
其實以某個字段排序並不符合客戶要求,客戶要求大多是,某種型別資料排在前面,某種資料排第二,某種第三,但這裡的型別並不是乙個字段可以體現,而是一種邏輯。這裡我們為我們的主表建立兩個排序字段,s1 int s2 int 以 表為例 如果是獨家 則s1列則標記1,s2列則標記設定時間 int格式 如果是推...
複雜排序之歸併排序
歸併排序的時間複雜度是o nlogn 與快速排序和堆排序最大的不同是歸併排序是穩定的,但它需要額外的o n 的空間複雜度 利用遞迴的方法進行排序 void merge elementtype a,elementtype tmpa,int left,int mid,int right void mso...
排序 2 選擇排序
工具方法類 package mydatastructrueadndalgorith.three.arrsort 陣列為模板排序演算法中的一些公用的模板方法 建立人 曹雪坤 version 1.0.0 public class example 遍歷陣列 public static void show ...