1.快速排序 :核心思想:选出一个key当作基准元素,让数组左边是比key小的元素,右边是比key大的元素。
实现:
int PartSort(int * a,int left,int right)
{
int key = left;
//int key = GetMidIndex(a, left, right);
int s = a[key];
while (left < right)
{
while (left < right && a[right] >= a[key])
--right;
while (left < right && a[left]<=a[key])
left++;
swap(&a[left], &a[right]);
}
swap(&a[left], &a[key]);
return left;
}
void QuikeSort(int *a,int left, int right){
if (left >= right)return;
int key = PartSort(a, left, right);
QuikeSort(a, left, key - 1);
QuikeSort(a, key + 1, right);
}
//hoare版本
当选取区间左边元素作为key元素时,当数组有序时或者接近有序时时间杂度为O(N*N)
对次我们经行一个优化:3数取中。
//3数取中,避免顺序快排出现时间复杂度为O(n*n);
int GetMidIndex(int* a, int left, int right)
{
int mid = (left + right) / 2;
if (a[left] > a[mid])
{
if (a[right] > a[left])
return left;
else if (a[right] < a[mid])
return mid;
else
return right;
}
else //a[left]<a[mid]
{
if (a[right] > a[mid])return mid;
else if (a[left] > a[right]) return left;
else return right;
}
}
注意此时不能只修改原代码中的key,因为原代码选左边做key 右边先走才保证了俩个指针相遇时的元素比key小 ,修改后的part函数如下
int PartSort(int * a,int left,int right)
{
int begin = left;
int key = GetMidIndex(a, left, right);
int s = a[key];
swap(&a[left],&a[key]);
while (left < right)
{
while (left < right && a[right] >=s)
--right;
while (left < right && a[left]<=s)
left++;
swap(&a[left], &a[right]);
}
swap(&a[left], &a[begin]);
return left;
另外的是实现方式:
//挖坑法快速排序
int PartSort2(int* a, int left, int right)
{
int hole = a[left];//挖坑
// int hole = a[GetMidIndex(a, left, right)];
int space = left;
// int space = GetMidIndex(a, left, right);
while (left < right)
{
while (left < right && a[right] >= hole)
{
right--;
}
a[space] = a[right];
space = right;
while (left < right && a[left] <= hole)
{
left++;
}
a[space] = a[left];
space = left;
}
a[space] = hole;
return space;
}
void QuikeSort2(int* a, int left, int right)
{
if (left >= right)return;
int key = PartSort2(a, left, right);
QuikeSort2(a, left, key - 1);
QuikeSort2(a, key + 1, right);
}
//非递归实现快速排序
void QuikeSort3(int* a, int left, int right)
{
ST st;
StackInit(&st);
StackPush(&st, left);
StackPush(&st, right);
while (!Stackempty(&st))
{
int _right = Stacktop(&st);
StackPop(&st);
int _left = Stacktop(&st);
StackPop(&st);
int key= PartSort(a, _left, _right);
if (_left < key - 1)
{
StackPush(&st, _left);
StackPush(&st, key - 1);
}
if (key + 1 < _right)
{
StackPush(&st, key + 1);
StackPush(&st, _right);
}
}
StackDestory(&st);
}
//前后指针法
int PartSort4(int *a,int left,int right)
{
int mid = GetMidIndex(a, left, right);
swap(&a[left], &a[mid]);
int cur = left;
int prev = left + 1;
while (prev<= right)
{
if (a[prev] < a[left] && a[++cur] != a[prev])
swap(&a[prev], &a[cur]);
++prev;
// while(prev<=right&&a[prev] > a[left])prev++;
//cur++;
// swap(&a[cur], &a[prev]);
// prev++;
}
swap(&a[left], &a[cur]);
return cur;
}
void QuikeSort4(int* a, int left, int right)
{
if (left >= right)return;
int key = PartSort4(a, left, right);
QuikeSort4(a, left, key - 1);
QuikeSort4(a, key + 1, right);
}
//小区间优化
void QuikeSort5(int* a, int left, int right)
{
if (right - left + 1 <= 10)
{
InsertSort(a + left, right - left + 1);
}//子问题是这一类问题时按照这样的方式处理,注意是类,将子问题按照类来划分;
else {
int key = PartSort4(a, left, right);
QuikeSort2(a, left, key - 1);
QuikeSort2(a, key + 1, right);
}
}
归并排序:核心思想:分治
实现:
/归并排序,递归版本时间复杂度n*logn;
//递归的部分排序
//对子问题经行归并排序
void MergeSort(int* a, int begin, int end)
{
int* temp = (int*)malloc(sizeof(int) * (end - begin + 1));
_MergeSort(a, begin, end, temp);
}
void _MergeSort(int* a, int begin, int end, int* temp)
{
if (begin >= end)return;
int mid = begin + (end - begin) / 2;
//不能用mid-1否则会出现死循环,比如0,1。
_MergeSort(a, begin, mid, temp);
_MergeSort(a, mid + 1, end, temp);
//对子问题进行归并
int begin1 = begin; int end1 = mid;
int begin2 = mid + 1; int end2 = end;
int q = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
temp[q++] = a[begin1++];
else
temp[q++] = a[begin2++];
}
if (begin1 <= end1)
{
while (begin1 <= end1)
temp[q++] = a[begin1++];
}
if (begin2 <= end2)
{
while (begin2 <= end2)
temp[q++] = a[begin2++];
}
memcpy(a + begin, temp+begin, sizeof(int)*(end - begin + 1));
}
//由于是归并所以得额外开数组避免原数组被覆盖;
// 非递归实现归并排序;
//从左到右 区间长度为1的俩俩归并,区间长度为2的俩俩归并..区间为4的俩俩归并..最后归并完成;
void UnMergeSort(int* a, int begin, int end,int *temp)
{
int gap = 1;
int i = 1;
for (gap = 1; gap <end - begin+1; gap = gap * 2)
{
for (i = 0; i <= end; i = i += 2 * gap)
{
int begin1 = i; int end1 = i + gap - 1;
if (end1 > end)end1 = end;
int begin2 = end1 + 1; int end2 = begin2 + gap - 1;
if (begin2 > end) {
begin2 = 1;
end2 = 0;
//不存在下一个区间
}
if (end2 > end)end2 = end;
//归并
int q = begin1;
int left1 = begin1; int right1 = end1;
int left2 = begin2; int right2 = end2;
while (left1 <= right1 && left2 <= right2)
{
if (a[left1] < a[left2])
temp[q++] = a[left1++];
else
temp[q++] = a[left2++];
}
if (left1 <= right1)
{
while (left1 <= right1)
temp[q++] = a[left1++];
}
if (left2 <= right2)
{
while (left2 <= right2)
temp[q++] = a[left2++];
}
memcpy(a + begin1, temp + begin1, sizeof(int) * (q - begin1));
}
}
}