1、折半查詢
思想:分治策略。把n個元素分成個數大致相同的兩半,取a[n/2]與查詢的key相比,一直搜尋下去。
比如:總共有n個元素,每次查詢的區間大小就是n,n/2,n/4,…,n/2^k(接下來操作元素的剩餘個數),其中k就是迴圈的次數。
由於n/2^k取整後》=1,即令n/2^k=1,
可得k=log2n,(是以2為底,n的對數),所以時間複雜度可以表示o()=o(logn)
/*折半查詢,非遞迴
*/int binary_search(int *a, int n, int key) //
o(log n)
return
0;
} /*
折半查詢,遞迴實現
*/int binary_search2(int *a, int low, int high, int
key)
2、冒泡、選擇、快速、堆
void bubblesort(int a, intn)
//或者
void bubblesort(int a, int
n)————————————
比較次數:1+2+......+n-1
快速排序採用的思想是分治思想。
快速排序是找出乙個元素(理論上可以隨便找乙個)作為基準(pivot),然後對陣列進行分割槽操作,使基準左邊元素的值都不大於基準值,基準右邊的元素值 都不小於基準值,如此作為基準的元素調整到排序後的正確位置。遞迴快速排序,將其他n-1個元素也調整到排序後的正確位置。最後每個元素都是在排序後的正 確位置,排序完成。所以快速排序演算法的核心演算法是分割槽操作,即如何調整基準的位置以及調整返回基準的最終位置以便分治遞迴。
舉例說明一下吧,這個可能不是太好理解。假設要排序的序列為
2 2 4 9 3 6 7 1 5 首先用2當作基準,使用i j兩個指標分別從兩邊進行掃瞄,把比2小的元素和比2大的元素分開。首先比較2和5,5比2大,j左移
2 2 4 9 3 6 7 1 5 比較2和1,1小於2,所以把1放在2的位置
2 1 4 9 3 6 7 1 5 比較2和4,4大於2,因此將4移動到後面
2 1 4 9 3 6 7 4 5 比較2和7,2和6,2和3,2和9,全部大於2,滿足條件,因此不變
經過第一輪的快速排序,元素變為下面的樣子
[1] 2 [4 9 3 6 7 5]
之後,在把2左邊的元素進行快排,由於只有乙個元素,因此快排結束。右邊進行快排,遞迴進行,最終生成最後的結果。
int quicksort(int a, int left, intright)
int key =a[left];
int low =left;
int high =right;
while(low a[low] =a[high];
while(low < high && a[low] a[high] =a[low];
}a[low] =key;
quicksort(a,left,low-1
); quicksort(a,low+1
,right);
} o(nlog2n)----o(n^2)
基本思想為(大頂堆):
1)將初始待排序關鍵字序列(r1,r2....rn)構建成大頂堆,此堆為初始的無須區;
2)將堆頂元素r[1]與最後乙個元素r[n]交換,此時得到新的無序區(r1,r2,......rn-1)和新的有序區(rn),且滿足r[1,2...n-1]<=r[n];
3)由於交換後新的堆頂r[1]可能違反堆的性質,因此需要對當前無序區(r1,r2,......rn-1)調整為新堆,然後再次將r[1]與無序區最後乙個元素交換,得到新的無序區(r1,r2....rn-2)和新的有序區(rn-1,rn)。不斷重複此過程直到有序區的元素個數為n-1,則整個排序過程完成。
最好以及最壞都是o(nlog2n),空間複雜度o(1).
void adjustheap(int arr, int start, intend)
}}void heap_sort(int arr, int
len)
}void
main()
;
int len = (int)sizeof(arr) / sizeof(*arr);
heap_sort(arr, len);
for (int i = 0; i < len; i++)
cout
<< arr[i] << '';
cout
<}
下面演示最大堆:父節點大於等於子節點
輸入:4 10 3 5 1
構建堆的過程:
410 3
5 1
構建堆完成,現在需要變為大頂堆:
從下往上,
10已經是大於其子節點了,不需改動。往上,4小於
10,交換位置:
此時:10 4 3 5 1
堆為:10
4 3
5 1
從下往上,4小於
5,交換位置:
此時:10 5 3 4 1
堆為:10
5 3
4 1
交換根節點和最小
(最後的乙個,並不是數值上最小
)的結點,並刪除:
此時:1 5 3 4 10
堆為:1 ------- 1
5 3 5 3
4 10 4
刪除以後,繼續構建最大堆。從下往上,1和
5換位置(看上圖):
此時:5 1 3 4 10
堆為:5
1 3
4從下往上,1小於
4,交換位置:
此時:5 4 3 1 10
堆為:5
4 3
1交換根節點和最小結點,並刪除:
此時:1 4 3 5 10
堆為:1 ------- 1
4 3 4 3
5
從下往上,繼續構建最大堆。1和
4交換位置:
此時:4 1 3 5 10
堆為:4
1 3
交換根節點和最後乙個結點,並刪除(4和
3交換,刪掉4):
此時:3 1 4 5 10
堆為:3 --------- 3
1 4 1
剩下已是最大堆,不需構建,直接交換結點:
此時:1 3 4 5 10
*****===附錄**********==
關於topk問題就不得不說了,型別有,找出前k個大的數、找出第k個大的數、找出重複k次的數
/*topk演算法實現
*/#include
/*調整小頂堆,pos:唯一違反堆性質的點的位置
*/void heapsort(int *a, const
int len, int
pos)
else
if (child + 1 == len) //
只有左孩子
else
break; //
陣列結束,調整完成
if (a[pos] >min)
else
break; //
已經是堆,無需調整}}
/*建立小頂堆
*/void create(int *b, const
intk) }
/*選出陣列中最大的k個數,存入陣列arr_k中
*/void top_k(const
int *a,const
int len, int *b, int
k) } /*
測試**
*/int
main()
;
int k 4
;
inti;
intb[k];
top_k(a,
9, b, k);
for (i = 0; i < k; ++i)
return0;
}
手寫 選擇排序
選擇排序 selection sort 是一種簡單直觀的排序演算法。它的工作原理 首先在未排序序列中找到最小 大 元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小 大 元素,然後放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。選擇排序 public class chec...
手寫氣泡排序
嚴格定義下的寫法 void bubblesort int array,int length void swap int a,int b 優化後的 void bubblesort int array,int length length 優化思想 當我們需要排序的陣列基本有序時,上面的 還會做出很多不必...
手寫堆排序
堆排序是乙個不穩定排序但是其最好最壞的時間複雜度為nlogn。所謂的堆其實就是乙個完全二叉樹的結構其主要特點是所有的子樹中父節點一定大於子節點。堆排的主要思想是將序列構造成乙個大頂堆,堆頂一定是整個序列中最大值然後將最大值與最後乙個數值交換,之後又將剩下的n 1個元素構造成乙個大頂堆之後在依次向與之...