排序
常见排序
- 插入排序:直接插入排序,希尔排序
- 选择排序:选择排序,堆排序
- 交换排序:冒泡排序,快速排序(快排)
- 归并排序:归并排序
插入排序
- 直接插入排序
性能: 时间O(n^2) /空间O(1)/ 稳定
void insertsort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)
{
int end = i;
int tem = a[end + 1];
while (end >= 0)
{
if (tem < a[end])
{
a[end + 1] = a[end];
}
else
break;
end--;
}
a[end + 1] = tem;
}
}
- 希尔排序
性能:时间O(nlogn)~O(n^2)/空间O(1)/不稳定
注:与直接插入一样,只是改变了gap的值,处理大量数据的时候可以让大的数字快速到达后面去
void shellsort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 2;
//gap=gap/3+1;
for (int i = 0; i < n - gap; i++)
{
int end = i;
int temp = a[end + gap];
while (end >= 0)
{
if (a[end] > temp)
{
a[end + gap] = a[end];
}
else
break;
end -= gap;
}
a[end+gap] = temp;
}
}
}
选择排序
- 选择排序
性能:时间O(n^2)/空间O(1)/不稳定
注:也可以在原数组里面操作找出最大最小值并记入最大最小值处的下标,然后与前后位置的元素交换
void SelectSort(int* a, int n)
{
int* p = (int*)malloc(sizeof(int) * n);
for (int i = 0; i <= n / 2; i++)
{
int minn = a[i], maxx = a[i];
for (int j = i; j < n ; j++)
{
if (minn > a[j])
{
minn = a[j];
}
if (maxx < a[j])
{
maxx = a[j];
}
}
p[i] = minn;
p[n - 1 - i] = maxx;
}
memcpy(a, p, sizeof(int) * n);
}
- 堆排序
性能:时间O(nlogn)/空间O(1)/不稳定
注意:建堆要与排序方式相反,使用向下建堆的方式建堆速度更快
void AdjustDwon(int* a, int n, int root)
{//大堆
int child = root * 2 + 1;
while (child < n)
{//判断左右儿子谁更大
if (child + 1 < n && a[child] < a[child + 1])
child++;
if (a[root] < a[child])
{
Swap(&a[root], &a[child]);
root = child;
child = root * 2 + 1;
}
else
break;
}
}
void HeapSort(int* a, int n)
{//用数组建堆
for (int i = (n-1-1) / 2; i >= 0; i--)
AdjustDwon(a, n, i);
int end = n - 1;
//将最大的堆顶与数组尾元素交换
while (end)
{
Swap(&a[0], &a[end]);
AdjustDwon(a, end, 0);
end--;
}
}
交换排序
- 冒泡排序
性能:时间O(n^2)/空间O(1)/稳定
注:可以添加一个flag去判断这一趟有没有交换,没有说明以排完序,可以结束排序了
void BubbleSort(int* a, int n)
{
for(int i=0;i<n;i++)
for (int j = 0; j < n - i-1; j++)
{
if (a[j] < a[j + 1])
{
Swap(&a[j], &a[j + 1]);
}
}
}
- 快速排序(快排)
性能:时间O(nlogn)/空间 O(logn)~O(n)/不稳定
注:可以有多种方法去排序,这里采用的最常见的一种方法,快排数据小于10的时候可以采用直接插入,相比于在函数递归性能更佳,添加三数取中,使所取数据更加有有效性,样例采用递归方式实现
详细见下篇文章:quicksort详解
int getmi(int* a, int l, int r)
{
int mid = (l + r) / 2;
if (a[mid] < a[l])
{
if (a[mid] > a[r])
return mid;
else if (a[r] > a[l])
return l;
else
return r;
}
else
{
if (a[l] > a[r])
return l;
else if (a[r] > a[mid])
return mid;
else
return r;
}
}
int PartSort1(int* a, int left, int right)
{
int mid = getmi(a, left, right);
Swap(&a[mid], &a[left]);
int k = a[left];
int l = left+1;
int r = right;
while (l < r)
{
while (l<r&&a[r] >= k)
r--;
while (l<r&&a[l] <= k)
l++;
Swap(&a[l], &a[r]);
}
Swap(&a[l], &a[left]);
return l;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
if (right - left + 1 < 10)
{
InsertSort(a, right - left + 1);
}
else
{
int k=PartSort1(a, left, right);
QuickSort(a, left, k - 1);
QuickSort(a, k+1,right);
}
}
归并排序
- 归并排序
性能:时间O(nlogn)/空间O(n)/稳定
注:每次归并后一定要将数据赋值回原数组,样例采用递归方式
void _mergesort(int* a, int l,int r, int* p)
{
if (l >= r)
return;
int mid = (l + r) / 2;
_mergesort(a, l, mid, p);
_mergesort(a, mid + 1, r, p);
int c = l;
int b1 = l, e1 = mid;
int b2 = mid + 1, e2 = r;
while (b1 <= e1 && b2 <= e2)
{
p[c++] = a[b1] < a[b2] ? a[b1++] : a[b2++];
}
while (b1 <= e1)
p[c++] = a[b1++];
while (b2 <= e2)
p[c++] = a[b2++];
memcpy(a + l, p + 1, sizeof(int) * (r - l + 1));
}
void MergeSort(int* a, int n)
{
int* p = (int*)malloc(sizeof(int));
if (p == NULL)
{
perror("MegeSort");
exit(-1);
}
_mergesort(a,0, n-1, p);
free(p);
}
特殊排序
- 计数排序
性能:与数据有关,擅长处理范围小的数据,遇强则强实力不详
void CountSort(int* a, int n)
{
int minn, maxx;
minn = maxx = a[0];
for (int i = 1; i < n; i++)
{
minn = min(minn, a[i]);
maxx = max(maxx, a[i]);
}
int* p = (int*)malloc(sizeof(maxx - minn + 1));
memset(p, 0, sizeof(sizeof(maxx - minn + 1)));
for (int i = 0; i < n; i++)
p[a[i]-minn]++;
int c = 0;
for (int i = 0; i < maxx - minn + 1; i++)
while (p[i]--)
a[c++] = i+maxx-minn+1;
free(p);
}
稳定性:指排序后相同元素的相对顺序是否发生改变