算法改变人生 2019-06-28
冒泡排序、插入排序、选择排序这三种算法的时间复杂度都为 $O(n^2)$,只适合小规模的数据。今天,我们来认识两种时间复杂度为 $O(nlogn)$ 的排序算法——归并排序(Merge Sort)和快速排序(Quick Sort),他们都用到了分治思想,非常巧妙。

递推公式: merge_sort(p…r) = merge(merge_sort(p…q), merge_sort(q+1…r)) 终止条件: p >= r 不用再继续分解

// O(n(logn))
void Merge_Sort(float data[], int left, int right, float sorted_data[])
{
if(left < right)
{
int mid = (left + right) / 2;
Merge_Sort(data, left, mid, sorted_data);
Merge_Sort(data, mid+1, right, sorted_data);
Merge_Array(data, left, mid, right, sorted_data);
}
}
void Merge_Array(float data[], int left, int mid, int right, float temp[])
{
int i = left, j = mid + 1;
int k = 0;
// 从子数组的头开始比较
while(i <= mid && j <= right)
{
if (data[i] <= data[j])
{
temp[k++] = data[i++];
}
else
{
temp[k++] = data[j++];
}
}
// 判断哪个子数组还有元素,并拷贝到 temp 后面
while(i <= mid)
{
temp[k++] = data[i++];
}
while(j <= right)
{
temp[k++] = data[j++];
}
// 将 temp 中的数据拷贝到原数组对应位置
for(i = 0; i < k; i++)
{
data[left+i] = temp[i];
}
}$$ T(1) = C $$
$$T(n) = 2*T(\frac{n}{2}) + n, n>1$$
$$T(n) = 2*T(\frac{n}{2}) + n$$
$$ = 2*[2*T(\frac{n}{4}) + \frac{n}{2}] + n = 4*T(\frac{n}{4}) + 2*n $$
$$= 4*[2*T(\frac{n}{8}) + \frac{n}{4}] + 2*n = 8*T(\frac{n}{8}) + 3*n $$
$$......$$
$$= 2^k * T(\frac{n}{2^k}) + k * n$$
$$......$$
当 $\frac{n}{2^k} = 1$时, $k = log_2n$,代入上式得:
$$ T(n) = n * C + nlog_2n$$
用大 O 标记法来表示,归并排序的时间复杂度为 $O(nlogn)$。

递推公式: quick_sort(p…r) = quick_sort(p…q-1) + quick_sort(q+1, r) 终止条件: p >= r


// O(n(logn))
void Quick_Sort(float data[], int left, int right)
{
if (left < right)
{
int i = left, j = left;
int pivot = data[right];
for (j = left; j < right; j++)
{
if (data[j] < pivot)
{
int temp = data[i];
data[i] = data[j];
data[j] = temp;
i++;
}
}
data[j] = data[i];
data[i] = pivot;
Quick_Sort(data, left, i-1);
Quick_Sort(data, i+1, right);
}
}
// O(n(logn))
void Quick_Sort(float data[], int left, int right)
{
if (left < right)
{
int i = left, j = right;
int pivot = data[i];
while(i < j)
{
while(i < j && data[i] <= pivot) // 从左往右找到第一个比 pivot 大的数
{
i++;
}
if(i < j)
{
data[j--] = data[i];
}
while(i < j && data[j] >= pivot) // 从右往左找到第一个比 pivot 小的数
{
j--;
}
if(i < j)
{
data[i++] = data[j];
}
}
data[i] = pivot; // i=j
Quick_Sort(data, left, i-1);
Quick_Sort(data, i+1, right);
}
}获取更多精彩,请关注「seniusen」! 
排序是将一串数据按照其某个或者某些关键字的大小进行递增或递减排列的操作我,通常指的排序是升序,排序方式是原地排序。即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并