文章目錄
1.mergeSort
優化
應用:逆序對
// merge函數求出在arr[l...mid]和arr[mid+1...r]有序的基礎上, arr[l...r]的逆序數對個數
long long __merge( int arr[], int l, int mid, int r){
int *aux = new int[r-l+1];
for( int i = l ; i <= r ; i ++ )
aux[i-l] = arr[i];
// 初始化逆序數對個數 res = 0
long long res = 0;
// 初始化,i指向左半部分的起始索引位置l;j指向右半部分起始索引位置mid+1
int j = l, k = mid + 1;
for( int i = l ; i <= r ; i ++ ){
if( j > mid ){ // 如果左半部分元素已經全部處理完畢
arr[i] = aux[k-l];
k ++;
}
else if( k > r ){ // 如果右半部分元素已經全部處理完畢
arr[i] = aux[j-l];
j ++;
}
else if( aux[j-l] <= aux[k-l] ){ // 左半部分所指元素 <= 右半部分所指元素
arr[i] = aux[j-l];
j ++;
}
else{ // 右半部分所指元素 < 左半部分所指元素
arr[i] = aux[k-l];
k ++;
// 此時, 因爲右半部分k所指的元素小
// 這個元素和左半部分的所有未處理的元素都構成了逆序數對
// 左半部分此時未處理的元素個數爲 mid - j + 1
res += (long long)(mid - j + 1);
}
}
delete[] aux;
return res;
}
// 求arr[l..r]範圍的逆序數對個數
long long __inversionCount(int arr[], int l, int r){
if( l >= r )
return 0;
int mid = l + (r-l)/2;
// 求出 arr[l...mid] 範圍的逆序數
long long res1 = __inversionCount( arr, l, mid);
// 求出 arr[mid+1...r] 範圍的逆序數
long long res2 = __inversionCount( arr, mid+1, r);
return res1 + res2 + __merge( arr, l, mid, r);
}
// 遞歸求arr的逆序數對個數
long long inversionCount(int arr[], int n){
return __inversionCount(arr, 0, n-1);
}
2.quickSort
2.1 一次partition操作
2.2 partition操作方式1
實現方式
//arr[l...p-1] <= arr[p] <= arr[p+1...r]
template <typename T>
int partition(T arr[], int l, int r)
{
int j = l;
int i = l+1;
while(i <= r)
{
if(arr[i] < arr[l])
{
swap(arr[j+1], arr[i]);
j++;
}
i++;
}
swap(arr[l], arr[j]);
return j;
}
//對arr[l...r]排序
template <typename T>
void __quickSort(T arr[], int l, int r)
{
if(l >= r) return ;
int p = partition(arr, l, r);
__quickSort(arr, l, p-1);
__quickSort(arr, p+1, r);
}
template <typename T>
void quickSort(T arr[], int n)
{
__quickSort(arr, 0, n-1);
}
優化
2.3 存在問題(數組近乎有序、數組存在大量重複元素)
快排退化爲O(n^2)的原因是因爲Partition時沒有很好均分數組
2.3.1 數組近乎有序
解決方法
2.3.2 數組存在大量重複元素
解決方法1
解決方法2
template <typename T>
void __quickSort3Ways(T arr[], int l, int r){
// 對於小規模數組, 使用插入排序進行優化
if( r - l <= 15 ){
insertionSort(arr,l,r);
return;
}
// 隨機在arr[l...r]的範圍中, 選擇一個數值作爲標定點pivot
swap( arr[l], arr[rand()%(r-l+1)+l ] );
T v = arr[l];
int lt = l; // arr[l+1...lt] < v
int gt = r + 1; // arr[gt...r] > v
int i = l+1; // arr[lt+1...i) == v
while( i < gt ){
if( arr[i] < v ){
swap( arr[i], arr[lt+1]);
i ++;
lt ++;
}
else if( arr[i] > v ){
swap( arr[i], arr[gt-1]);
gt --;
}
else{ // arr[i] == v
i ++;
}
}
swap( arr[l] , arr[lt] );
__quickSort3Ways(arr, l, lt-1);
__quickSort3Ways(arr, gt, r);
}
template <typename T>
void quickSort3Ways(T arr[], int n){
srand(time(NULL));
__quickSort3Ways( arr, 0, n-1);
}