# （数据结构）七种常用的排序算法分析及代码实现（下）——快速排序及归并排序

## 快速排序

### 思路分析

• 单趟快排，将区间分成较大和较小两部分。
• 利用迭代循环，不断细化区间。
• 对区间进行合并，从而实现整体有序。

### 代码实现

//左右指针法
int PartSort1(int* a, size_t left, size_t right)
{
int begin = left;
int end = right;
int& key = a[end];

while (begin < end)
{
while (begin < end
&& a[begin] <= key)
++begin;
while (begin < end
&& a[end] >= key)
--end;

if (begin < end)
{
swap(a[begin],a[end]);
}
}

swap(a[begin],key);

return begin;
}

//快速排序
void QuickSort(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;

int div = PartSort1(a, left, right);

QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}

//三数取中
int GetMidIndex(int* a, size_t left, size_t right)
{
int mid = left + ((right - left) >> 1);
if (a[left] < a[mid])
{
if (a[mid] < a[right])
return mid;
else if (a[left] > a[right])
return left;
else
return right;
}

else//left >= mid
{
if (a[mid] > a[right])
return  mid;
else if (a[left] < a[right])
return left;
else
return right;
}
}

//左右指针法
int PartSort1(int* a, size_t left, size_t right)
{
int begin = left;
int end = right;

int mid = GetMidIndex(a, left, right);
swap(a[mid], a[end]);

int& key = a[end];

while (begin < end)
{
while (begin < end
&& a[begin] <= key)
++begin;
while (begin < end
&& a[end] >= key)
--end;

if (begin < end)
{
swap(a[begin], a[end]);
}
}

swap(a[begin], key);

return begin;
}

//快速排序
void QuickSort(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;

int div = PartSort1(a, left, right);

QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}

//挖坑法
int PartSort2(int* a, int left, int right)
{
assert(a);
int begin = left;
int end = right;
int key = a[end];

while (begin < end)
{
while (begin < end
&& a[begin] <= key)
++begin;
a[end] = a[begin];

while (begin < end
&& a[end] >= key)
--end;
a[begin] = a[end];
}

a[begin] = key;

return begin;
}

//快速排序
void QuickSort(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;

int div = PartSort2(a, left, right);

QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}

//前后指针法
int PartSort3(int* a, int left, int right)
{
assert(a);
int cur = left;
int prev = left - 1;

while (cur < right)
{
if (a[cur] < a[right]
&& ++prev != cur)
swap(a[prev], a[cur]);
cur++;
}
swap(a[++prev], a[right]);

return prev;
}

//快速排序
void QuickSort(int* a, int left, int right)
{
assert(a);
if (left >= right)
return;

int div = PartSort3(a, left, right);

QuickSort(a, left, div - 1);
QuickSort(a, div + 1, right);
}

//非递归实现快速排序
void QuickSortNonR(int* a, int left, int right)
{
stack<int> s;
s.push(right);
s.push(left);

while (!s.empty())
{
int begin = s.top();
s.pop();
int end = s.top();
s.pop();

int div = PartSort1(a, begin, end);
if (begin < div - 1)
{
s.push(div - 1);
s.push(begin);
}
if (div + 1 < end)
{
s.push(end);
s.push(div + 1);
}
}
}

### 时间复杂度

• 因为会对数组进行不对的分裂再合并
• 所以会有平均时间复杂度为O(N*lgN)
• 当数组有序时，会出现最坏时间复杂度0(N^2)
• 但因为三数取中法的引进，即针对有序数列进行了优化，所以我们在这里不看最坏时间复杂度
• 因此，快速排序的时间复杂度我们认为是0(N*lgN)

## 归并排序

### 思路分析

1、根据递归&迭代的思想来实现此排序
2、将区间分成两个小区间，对两个区间进行重新排序，比较排序后的结果放到一个新的数组里面。
3、小区间不断合并，不断合并，最后得到的即为有序序列。

### 代码实现

//归并排序
void _MergeSort(int* a, int left, int right, int* tmp)
{
assert(a);
if (left >= right)
return;

int mid = left + ((right - left) >>1);

_MergeSort(a, left, mid, tmp);
_MergeSort(a, mid + 1, right, tmp);

int begin1 = left, end1 = mid;
int begin2 = mid + 1, end2 = right;
int index = left;

while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1]<a[begin2])
{
tmp[index++] = a[begin1++];
}
else
{
tmp[index++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}

memcpy(a+left, tmp + left, sizeof(int)*sizeof(right - left + 1));

}

void MergeSort(int* a,size_t n)
{
assert(a);
int* tmp = new int[n];
_MergeSort(a, 0, n, tmp);
//delete[] tmp;
}

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120