算法练习day6——190323(求中位数、堆排序、稳定性)
1.求中位數
有一個流,不斷輸出數,然后會不停地詢問已輸出的那些書的中位數。
解決方法:用一個大根堆,一個小根堆存那些已輸出的數。
- 大根堆中存儲較小的N/2個數;
- 小根堆中存儲較大的N/2個數;
- 這樣,中位數=(大根堆的根+小根堆的根)/2;
- 大根堆的根是較小的N/2中最大的;
- 小根堆的根是較大的N/2中最小的;
- 兩者剛卡在數據的中間。
具體步驟:
- 輸出的第一個數先放在大根堆;
- 后面輸出的數小于等于大根堆的根,則如大根堆,然后調整堆;
- 若大于大根堆中的根,則入小根堆,調整堆;
- 若大根堆中的節點數比小根堆中的節點數多2個,則將大根堆的根取出,如小根堆;反之亦然。
- 用heapsize記錄已形成的堆的大小;
- 取根的結果:
- 大根堆中最大的進入小根堆,滿足小根堆中的數都大于大根堆中的數;
- 小根堆中最小的進入大根堆,滿足小根堆中的數都大于大根堆中的數。
如何彈出大頂堆的根(小根堆類似):
- 最后一個元素和堆頂元素交換;
- 堆范圍-1;
- 再調整堆。
比如:
1、交換6和1:
2、堆范圍-1(0~4變為0~3):
3、調整堆:
調整之后:
2.堆的重要性
幾乎一切的貪心結構都是用堆完成的。
優先級隊列就是堆!
3.堆排序
步驟:
代碼實現:
package Sort;public class HeapSort {public static void main(String[] args) {int[] array= {2,1,3,6,0,4};for(int i=0;i<array.length;i++)System.out.print(array[i]+" ");System.out.println();heapsort(array);for(int i=0;i<array.length;i++)System.out.print(array[i]+" ");}public static void heapsort(int[] arr) {if(arr==null||arr.length<2)return;for(int i=0;i<arr.length;i++) {heapInsert(arr,i);}int heapsize=arr.length;swap(arr,0,--heapsize);while(heapsize>0) {heapify(arr,0,heapsize);swap(arr,0,--heapsize);}}public static void heapInsert(int[] arr,int i) {while(arr[i]>arr[(i-1)/2]) {swap(arr,i,(i-1)/2);i=(i-1)/2;//變為自己的父節點,繼續向上比較}}public static void heapify(int[] arr,int i,int heapsize) {int left=i*2+1;while(left<heapsize) {if(left+1<heapsize) {int largest=max(arr,i,left,left+1);if(largest==arr[i])//它已經是最大的了break;else if(largest==arr[left]) {swap(arr,i,left);i=left;}else {swap(arr,i,left+1);i=left+1;}left=2*i+1;}else {if(arr[i]<arr[left]) {swap(arr,i,left);i=left;left=i*2+1;}elsebreak;}}}public static void swap(int[] arr,int i,int j) {int temp=arr[i];arr[i]=arr[j];arr[j]=temp;}public static int max(int[] arr,int i,int j,int k) {int num=arr[i]>arr[j]?arr[i]:arr[j];return num>arr[k]?num:arr[k];} }運行結果:
4.排序算法的穩定性
4.1 3個常規的的排序
4.1.1 冒泡排序
可以做到穩定
相等時不交換,讓后面的數繼續往后比較即可。
第一次比較之后,交換:
第二次比較之后,交換:
第三次比較之后,相等,不交換:
讓后面的7再和之后的數進行比較,則可保證這兩個7的相對位置不變。
4.1.2 插入排序
可是實現為穩定的。
和前面數相等時,不交換。
第一次比較之后,交換:
第二次比較,相等,不交換,停止:
此時兩個6的相對位置沒變。
4.1.3 選擇排序
無法做到穩定性。
第一次比較之后,0個第一個5進行交換:
現在第一個5和其他5的相對位置發生了變化,它從第一個變為了第四個。——不穩定。
4.2?d的三個排序
4.2.1 歸并排序
可以做到穩定。
merge時,若左=右,則先拷貝左,保證右和左相同的值不會跨到左的前面。
p1和p2指向的兩個位置的值相等,都為3,先把p1指向的3拷貝到輔助數組;
p1右移;
此時p1指向的還為3,則繼續將它拷貝到輔助數組;
p1右移;
p1的值4>3,將p2指向的3拷貝到輔助數組。
這種方式即可保證三個3的相對位置不變。
4.2.2 快速排序
不能保證穩定性。
因為partation過程無法實現穩定性。
荷蘭國旗問題同理。
若目前情況如下所示:
此時,要處理的元素是3,它小于4,將它與最前面的4進行交換:
第一個4就變成了第三個4,不穩定。
題:奇數放在數組左邊, 偶數放在數組右邊, 還要求原始的相對次序不變。
此題類似于快排的Partation過程。
若要實現,<01 stable sort>有方法可解決,但特變難。
4.2.3 堆排序
無法實現穩定性。
因為交換過程中不關心相等值。
原始堆如下:
此時插入一個5:
需要對堆進行調整:
首先就是把5和它的父節點的4進行交換;
目前,4的相對位置已發生變化,所以堆排序不是穩定的。
4.3
| √ |
| √ |
| × |
| √ |
| × |
| × |
表格總結
?
4.4 穩定性的意義
可以利用前面比較的結果。
比如實際應用中,要對學生的一系列屬性進行排序,具體信息如下:
首先按成績從高到低進行排序:
再按班級進行排序:
則按班級排好之后,班級內的成績也是按從高到低次序排列的,利用了前面按成績排序的結果。
- 班級號相同的,按原始的相對位置(成績從高到低的次序)調到了一塊。
5. 工程中的綜合排序算法
5.1 數組很大
先對數組內的元素類型進行判斷:
5.1.1 元素類型為基本類型
則相同值之間無差異,不用氛原始順序,所以可以采用不穩定的排序算法。
使用快速排序。
5.1.2 元素類型為自定義數據類型
例如:學生,需要先按成績排序,再按班級號排序。即成績相同的個體之間也是有差異的。
需要保證此次排序之前相等值的原始順序。需要使用穩定的排序算法。
使用歸并排序。
5.2 若數組比較短,<60
使用插入排序。
雖然它是,但是常數項極低,在元素個數小的情況下,非常有效。
?
?
?
總結
以上是生活随笔為你收集整理的算法练习day6——190323(求中位数、堆排序、稳定性)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法练习day5——190322(快排、
- 下一篇: 算法练习day7——190325(比较器