文章目录
一、冒泡排序
1、步骤
左边大于右边交换一趟排下来最大的在右边
2、思路
动图演示如下:
3、代码实现
void BubbleSort(int* a, int n)
{
int exchange = 0;
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - 1 - i; j++)
{
if (a[j] > a[j + 1])
{
Swap(&a[j], &a[j + 1]);
exchange = 1;
}
}
if (exchange == 0)
{
break;
}
}
}
4、特性总结
1、时间复杂度:O(N^2)
2、空间复杂度O(1)
3、稳定性:稳定
5、实现结果
二、快速排序
1、步骤
任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。
2、思路
hoare版(左右指针法)
挖坑法
前后指针法
3、代码实现
三数取中对代码进行优化
void GetMid(int* a, int left, int right)
{
int mid = (left + right) / 2;
if (a[left] < a[mid])
{
if (a[mid]<a[right])
{
return mid;
}
else if (a[left] < a[right])//mid最大
{
return right;
}
else
{
return left;
}
}
//a[left] > a[mid]
else
{
if (a[mid] > a[right])
{
return mid;
}
else if (a[left] > a[right])//mid最小
{
return right;
}
else
{
return left;
}
}
}
快排优化
减少递归调用函数开辟的空间
void QuickSort(int* a, int begin, int end)
{
if (begin >= end)
return;
if (end - begin + 1 > 10)
{
int keyi = PartSort3(a, begin, end);
QuickSort(a, begin, keyi - 1);
QuickSort(a, keyi + 1, end);
}
else
{
Insertsort(a + begin, end - begin + 1);
}
}
hoare(左右指针法)
//hoare版
int PartSort1(int* a, int left, int right)
{
int midi = GetMidi(a, left, right);
Swap(&a[midi], &a[left]);
int keyi = left;
while (left < right)
{
//找小
while (left < right && a[right] >= a[keyi])
{
--right;
}
//找大
while (left < right && a[left] <= a[keyi])
{
++left;
}
Swap(&a[left], &a[right]);
}
Swap(&a[keyi], &a[left]);
return left;
}
void QuickSort(int* a, int begin, int end)
{
if (begin >= end)
return;
if (end - begin + 1 > 10)
{
int keyi = PartSort3(a, begin, end);
QuickSort(a, begin, keyi - 1);
QuickSort(a, keyi + 1, end);
}
else
{
Insertsort(a + begin, end - begin + 1);
}
}
挖坑法
//挖坑法
int PartSort2(int* a, int left, int right)
{
int midi = GetMidi(a, left, right);
Swap(&a[midi], &a[left]);
int key = a[left];
int hole = left;
while (left < right)
{
while (left < right && a[right] >= key)
{
right--;
}
a[hole] = a[right];
hole = right;
while (left < right && a[left] <= key)
{
left++;
}
a[hole] = a[left];
hole = left;
}
a[hole] = key;
return left;
}
void QuickSort(int* a, int begin, int end)
{
if (begin >= end)
return;
if (end - begin + 1 > 10)
{
int keyi = PartSort3(a, begin, end);
QuickSort(a, begin, keyi - 1);
QuickSort(a, keyi + 1, end);
}
else
{
Insertsort(a + begin, end - begin + 1);
}
}
前后指针法
//前后指针法
int PartSort3(int* a, int left, int right)
{
int midi = GetMidi(a, left, right);
Swap(&a[midi], &a[left]);
int keyi = left;
int prev = left;
int cur = left + 1;
while (cur <= right)
{
if (a[cur] < a[keyi]&& prev++ != cur)
{
Swap(&a[cur], &a[prev]);
}
++cur;
}
Swap(&a[keyi], &a[prev]);
return prev;
}
void QuickSort(int* a, int begin, int end)
{
if (begin >= end)
return;
if (end - begin + 1 > 10)
{
int keyi = PartSort3(a, begin, end);
QuickSort(a, begin, keyi - 1);
QuickSort(a, keyi + 1, end);
}
else
{
Insertsort(a + begin, end - begin + 1);
}
}
非递归实现
借助栈实现
//快排非递归
void QuickSortNonR(int* a, int begin, int end)
{
ST st;
STInit(&st);
STPush(&st, end);
STPush(&st, begin);
while (!STEmpty(&st))
{
int left = STTop(&st);
STPop(&st);
int right = STTop(&st);
STPop(&st);
int keyi = PartSort1(a,left, right);
if (keyi + 1 < right)
{
STPush(&st, right);
STPush(&st, keyi+1);
}
if (left<keyi-1)
{
STPush(&st, keyi-1);
STPush(&st, left);
}
}
STDestroy(&st);
}
4、特性总结
1、时间复杂度:O(N*logN)
2、空间复杂度:O(logN)
3、稳定性:不稳定 例如:5 0 5 7 10 5 8
5、实现结果
三、归并排序
1、步骤
分解:将待排序的数组不断分成两个子数组,直到每个子数组只有一个元素为止。
合并:将相邻的两个子数组合并成一个有序数组,直到最后只剩下一个有序数组为止
2、思路
动图演示如下:
3、代码实现
递归实现
void _MergeSort(int* a, int* tmp, int begin, int end)
{
if (end <= begin)
return;
int mid = (end + begin) / 2;
_MergeSort(a, tmp, begin, mid);
_MergeSort(a, tmp, mid + 1, end);
int begin1 = begin, end1 = mid;
int begin2 = mid + 1, end2 = end;
int index = begin;
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 + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
_MergeSort(a, tmp, 0, n - 1);
free(tmp);
}
非递归实现
void MergeSortNonR(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
int gap = 1;
while (gap < n)
{
for (int i = 0; i < n; i += 2 * gap)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
if (end2 >= n)
{
end2 = n - 1;
}
if (end1 >= n && begin2 >= n)
{
break;
}
int index = i;
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 + i, tmp + i, (end2-i+1) * sizeof(int));
}
gap *= 2;
}
free(tmp);
}
4、特性总结
时间复杂度:O(N*logN)
空间复杂度:O(N)
稳定性:稳定
5、实现结果
四、计数排序
1、步骤
1、统计相同元素出现次数
2、根据统计的结果将序列回收到原数组中
2、思路
动图演示如下:
3、代码实现
void CountSort(int* a, int n)
{
int min = a[0], max = a[0];
for (int i = 0; i < n; i++)
{
if (a[i] < min)
min = a[i];
if (a[i] > max)
max = a[i];
}
int range = max - min + 1;
int* count = (int*)malloc(sizeof(int) * range);
if (count == NULL)
{
perror("malloc fail");
return;
}
memset(count, 0, sizeof(int) * range);
// 统计数据出现次数
for (int i = 0; i < n; i++)
{
count[a[i] - min]++;
}
// 排序
int j = 0;
for (int i = 0; i < range; i++)
{
while (count[i]--)
{
a[j++] = i + min;
}
}
}
4、特性总结
1、时间复杂度:O(N+range)
2、空间复杂度:O(range)
3、稳定性:稳定