1 void merge(int arr[], int l, int m,int r) 2 { 3 int i = 0, j = 0, k =l; 4 int n1 = m - l + 1; //左邊步長 5 int n2 = r - m; //右邊步長 6 std::vector<int> vec_l(&arr[l], &arr[m+1]); 7 std::vector<int> vec_r(&arr[m+1], &arr[r+1]); 8 while (i < n1&&j < n2) 9 { 10 if (vec_l[i] <= vec_r[j]) 11 { 12 arr[k] = vec_l[i]; 13 i++; 14 } 15 else 16 { 17 arr[k] = vec_r[j]; 18 j++; 19 } 20 k++; 21 } 22 while (i<n1) 23 { 24 arr[k]= vec_l[i]; 25 i++; 26 k++; 27 } 28 29 while (j<n2) 30 { 31 arr[k] = vec_r[j]; 32 j++; 33 k++; 34 } 35 36 37 } 38 39 void mergeSort(int arr[], int l, int r) 40 { 41 if (l < r) 42 { 43 int m = l + (r - l) / 2; 44 45 mergeSort(arr, l, m); 46 mergeSort(arr, m + 1, r); 47 48 merge(arr, l, m, r); 49 } 50 }
再貼張排序的時間與空間復雜度的圖
總結:
為什么堆排序的時間復雜度理想卻很少被采用:
作者:qinzp
鏈接:https://www.zhihu.com/question/23873747/answer/327295185
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
-------------------------------------------------------------------
鏈接:https://www.zhihu.com/question/23873747/answer/327295185
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
-------------------------------------------------------------------
堆排序下,數據讀取的開銷變大。在計算機進行運算的時候,數據不一定會從內存讀取出來,而是從一種叫cache的存儲單位讀取。原因是cache相比內存,讀取速度非常快,所以cache會把一部分我們經常讀取的數據暫時儲存起來,以便下一次讀取的時候,可以不必跑到內存去讀,而是直接在cache里面找。
一般認為讀取數據遵從兩個原則:temporal locality,也就是不久前讀取過的一個數據,在之后很可能還會被讀取一遍;另一個叫spatial locality,也就是說讀取一個數據,在它周圍內存地址存儲的數據也很有可能被讀取到。因此,在讀取一個單位的數據(比如1個word)之后,不光單個word會被存入cache,與之內存地址相鄰的幾個word,都會以一個block為單位存入cache中。另外,cache相比內存小得多,當cache滿了之后,會將舊的數據剔除,將新的數據覆蓋上去。
在進行堆排序的過程中,由於我們要比較一個數組前一半和后一半的數字的大小,而當數組比較長的時候,這前一半和后一半的數據相隔比較遠,這就導致了經常在cache里面找不到要讀取的數據,需要從內存中讀出來,而當cache滿了之后,以前讀取的數據又要被剔除。
簡而言之快排和堆排讀取arr[i]這個元素的平均時間是不一樣的。
一般認為讀取數據遵從兩個原則:temporal locality,也就是不久前讀取過的一個數據,在之后很可能還會被讀取一遍;另一個叫spatial locality,也就是說讀取一個數據,在它周圍內存地址存儲的數據也很有可能被讀取到。因此,在讀取一個單位的數據(比如1個word)之后,不光單個word會被存入cache,與之內存地址相鄰的幾個word,都會以一個block為單位存入cache中。另外,cache相比內存小得多,當cache滿了之后,會將舊的數據剔除,將新的數據覆蓋上去。
在進行堆排序的過程中,由於我們要比較一個數組前一半和后一半的數字的大小,而當數組比較長的時候,這前一半和后一半的數據相隔比較遠,這就導致了經常在cache里面找不到要讀取的數據,需要從內存中讀出來,而當cache滿了之后,以前讀取的數據又要被剔除。
簡而言之快排和堆排讀取arr[i]這個元素的平均時間是不一樣的。
----------------------------------------------------------------------
快速排序最優的情況就是每一次取到的元素都剛好平分整個數組,最優的情況下時間復雜度為:O( nlogn )
最差的情況就是每一次取到的元素就是數組中最小/最大的,這種情況其實就是冒泡排序了(每一次都排好一個元素的順序),快速排序最差的情況下時間復雜度為:O( n^2 )
最優的情況下空間復雜度為:O(logn) ;每一次都平分數組的情況
最差的情況下空間復雜度為:O( n ) ;退化為冒泡排序的情況(用來存儲哨兵變量的臨時值)
----------------------------------------------------------------------------
快排數據越無序越快(加入隨機化后基本不會退化),平均常數最小,不需要額外空間,不穩定排序。
歸排速度穩定,常數比快排略大,需要額外空間(還有個東西叫多路歸並),穩定排序。(歸並排序需要額外空間記錄子數組的值)
------------------------------------------------------------------------
實際問題中歸並排序並不比快排應用少。快排需要遞歸,就這一點基就可以在許多大數據應用場景把它槍斃了。而歸並排序的scale能力比快排好很多,可以分布式處理,其實很受歡迎的