void
selectionsort
(int arr,
int n)
}swap
(arr[minidx]
,arr[times]);
times++;}
}
對於近乎有序的陣列,排序效率很高,時間複雜度接近o(n)
// 基礎版
void
insertionsort
(int arr,
int n)}}
// 優化版
// 減少不斷交換中的重複賦值
void
insertionsort
(int arr,
int n)
arr[j]
=temp;
}}
o(nlogn):將全部元素分為logn層,每層的時間複雜度為o(n)
缺點是多使用o(n)個儲存空間
自頂向下的歸併排序
// 遞迴實現歸併排序
void
mergesort
(int arr,
int n)
// 自頂向下
// 基礎版
void
__mergesort
(int arr,
int l,
int r)
// 優化版
void
__mergesort
(int arr,
int l,
int r)
int mid=
(l+r)/2
;__mergesort
(arr, l, mid)
;__mergesort
(arr, mid+
1, r)
;// 優化2:只有arr[mid]>arr[mid+1],才歸併
// 對於近乎有序的陣列非常有效
if(arr[mid]
>arr[mid+1]
)__merge
(arr, l, mid, r);}
// 將arr[l, mid]和arr[mid+1, r]兩部分歸併
void
__merge
(int arr,
int l,
int mid,
int r)
else
if(j>r)
else
if(temp[i-l]
)else
}delete
temp;
}
自底向上的歸併排序:可以通過索引直接獲取元素,適合於對鍊錶排序。同時也是一種非遞迴實現的歸併排序
// 自底向上實現歸併排序
void
mergesortbu
(int arr,
int n)
}}
基礎版
缺點:對於近乎有序的陣列,時間複雜度會退化為o(n^2),因為每次選最左邊的元素作為標定點,導致分成的partition兩部分陣列長度差異較大,以此類推時間消耗巨大。
解決辦法:隨機選擇陣列中的元素作為標定點
void
quicksort
(t arr,
int n)
// 對arr[l,r]部分進行快速排序
void
__quicksort
(t arr,
int l,
int r)
// 小規模陣列用插入排序
if(r-l<=15)
int mid=
_partition
(arr, l, r)
;__quicksort
(arr, l, mid-1)
;__quicksort
(arr, mid+
1, r);}
// 返回j,使得arr[l,j-1]arr[j]
// 基礎版
int_partition
(t arr,
int l,
int r)
swap
(arr[l]
, arr[j]);
return j;
}
若陣列中有大量重複元素,時間複雜度仍然會退化為o(n^2),因為大於標定點或小於標定點兩部分中,有一部分會包含有大量重複元素,導致陣列長度較長。
雙路快排
int
_parttion
(t arr,
int l,
int r)
// i在第乙個大於等於taget的位置,j在最後乙個小於等於target的位置
swap
(arr[l]
, arr[j]);
return j;
}
三路快排void
__quicksort3ways
(t arr,
int l,
int r)
// partition
swap
(arr[l]
, arr[
rand()
%(r-l+1)
+l])
; t target=arr[l]
;int lt=l;
// arr[l, lt] < target
int gt=r+1;
// arr[gt, r] > target
int i=l+1;
// arr[lt+1, i) == target
while
(i < gt)
swap
(arr[l]
, arr[lt]);
__quicksort3ways
(arr, l, lt-1)
;// 注意這裡是-1
__quicksort3ways
(arr, gt, r)
;}
非遞迴實現的快速排序void
__quicksort
(t arr,
int l,
int r)
int mid=
_partion
(arr, l, r);if
(mid-
1> l)
if(mid+
1< r)
}}
求乙個陣列中逆序對的數量。陣列中逆序對的數量可以衡量陣列的有序程度。
// 暴力解法
intinversioncount
(int arr,
int n)
}return num;
}// 歸併排序法
long
long
__merge3
(int arr,
int l,
int mid,
int r)
else
if(j > r)
if(arr[i]
> arr[j]
)else
}for
(int i =
0; i <
(r - l +1)
; i++
) arr[l + i]
= aux[i]
;delete
aux;
return count;
}long
long
__inversioncount3
(int arr,
int l,
int r)
return count;
}// 對於乙個大小為n的陣列, 其最大的逆序數對個數為 n*(n-1)/2, 非常容易產生整型溢位
long
long
inversioncount3
(int arr,
int n)
求乙個陣列中第n大的元素
int
__partition
(int arr,
int l,
int r)
swap
(arr[l]
, arr[j]);
return j;
}int
__selectkth
(int arr,
int l,
int r,
int k)
intselectkth
(int arr,
int n,
int k)
排序演算法 冒泡 插入 歸併 快排
整理了一下幾種常見的排序演算法,包括冒泡 插入 歸併 快排。還有另外幾種待整理 堆排序 希爾排序 桶排序 直接上 include include include using namespace std void swap int a,int b 最簡單的氣泡排序,時間複雜度o n n void bu...
排序演算法 快排,歸併
從陣列中隨機選乙個數,比這個數大的放右邊,比這個數小的放左邊。快排中的乙個細節 如果乙個數等於p的時候,既可以在左邊又可以在右邊。這麼做是為了避免如果陣列中所有的數都一樣,則會造成資料的不平衡。快排的目的是能夠使得左邊和右邊的數都差不多,這樣的話時間複雜度就不會退化到o n 2 而是o n logn...
排序演算法 歸併 快排
歸併排序的思想是分治法,如果想要將乙個陣列排序,那麼將這個陣列分為左區間和右區間,左區間一定是小於右區間的,再將左區間繼續劃分,右區間也繼續劃分。最後將排好序的陣列全都歸併起來,這樣聽起來像是從上向下劃分,其實歸併排序主要是是從下向上,合併的過程。先將單個元素的陣列歸併為兩個元素的有序陣列 再將包含...