认识O(NlogN)的排序
归并排序
归并排序(merge sort)的计算复杂性较冒泡排序要低一个数量级,其解题思路可概要如下:
- 当待排序数组的元素个数大于1时,认为该问题过于复杂,难以求解,将数组拆分成两个差不多大的子数组。
- 分别对拆分出来的子数组进行排序,得到有序的两个子数组。对子数组的排序过程是递归的,当子数组的元素个数大于1时,会进一步拆分成更小的子子数组。
- 将两个有序的子数组合并为整体有序的“原”数组。
void merge(int a[],int low, int mid, int high) {
int* t = (int*)malloc((high-low+1)*sizeof(int));
int i = low, j = mid + 1, k = 0;
while (i<=mid && j<=high){
if (a[i]<=a[j])
t[k++] = a[i++];
else
t[k++] = a[j++];
}
while (i<=mid)
t[k++] = a[i++];
while (j<=high)
t[k++] = a[j++];
for (i=low, k=0; i<=high; i++,k++)
a[i] = t[k];
free(t);
}
void mergeSort(int a[], int low, int high) {
if (low < high){
int mid = (low + high)/2;
mergeSort(a, low, mid);
mergeSort(a, mid+1, high);
merge(a, low, mid, high);
}
}
归并排序的拓展,小和问题与逆序对问题。
快速排序
快速排序在每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。
void quickSort(int left, int right, int *arr)
{
if(left >= right)
return;
int i, j, base, temp;
i = left, j = right;
base = arr[left]; //取最左边的数为基准数
while (i < j)
{
while (arr[j] >= base && i < j)
j--;
while (arr[i] <= base && i < j)
i++;
if(i < j)
{
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//基准数归位
arr[left] = arr[i];
arr[i] = base;
quickSort(left, i - 1, arr);//递归左边
quickSort(i + 1, right, arr);//递归右边
}
快速排序可以再进行加速,即将整个数组划分为三个区域[小于基准数,等于基准数,大于基准数],之后再对小于基准数与大于基准数的区域进行排序。
快速排序的拓展,荷兰国旗问题。