1.直接插入排序
直接插入排序的思想:将数组的第一个元素就看为有序数组,然后从数组第二个数开始进行排序,将第二个数(将要进行比较排序的值)进行临时存储(tmp),如果第一个数大于第二个数,那么就将较大的这个数往后挪动,较小数继续往前比较,直到较小数碰到比自己更小的值(表找到自己在数组的位置),或比较到数组起始位置(表本次排序的数是最小值)即停止。
- 时间复杂度:O(N^2)
- 空间复杂度:O(1)
void InsertSort(int* a, int n)
{
for (int i = 0; i < n-1; i++)//n-1防止越界比较
{
int end = i;
int tmp = a[end + 1];
while (end >= 0)//对比到最小位置
{
if (a[end] > tmp)
a[end + 1] = a[end];//大的往后挪
else
break;
end--;//下标--,只要a[end]比tmp大,就继续往前进行比较插入,直至比较到a[0]
}
a[end + 1] = tmp;//当比较到a[0],或者a[end] < tmp时,即代表tmp已经找到了自己对应的位置。
}
}
2.希尔排序
希尔排序本质上<直接插入排序>的pro plus max版,思想跟插排差不太多,但是在对数据的排序上却是快了很多,具体的行为就是对数据进行大量的预排序,到最后插入排序时效率非常高。
- 时间复杂度:O(N^1.3)
- 空间复杂度:O(1)
void ShellSort(int* a, int n)
{
int gap = n;
while (gap >= 1)
{
gap /= 2;
for (int i = 0; i < n - gap; i++)//n-gap防止越界
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)//依旧是判断到0
{
if (a[end] > tmp)
a[end + gap] = a[end];
else
break;
end -= gap;//这里不是end--,是end-gap步
}
a[end + gap] = tmp;
}
}
}
3.堆排序
堆排序是利用堆这种数据结构的特性,堆数据进行快速的筛选,堆这种数据结构虽然不能使数组很快的进行排序成序,但堆阔以很快的找出数据中最大或者最小的数据以此进行排序。
- 时间复杂度:O(N*logN)
- 空间复杂度:O(1)
void AdjustDown(int* a,int n ,int parent)//
{
int child = parent * 2 + 1;
while (child < n)
{
if (child + 1 < n && a[child] < a[child + 1])//判断越界
child++;
if (a[parent] < a[child])
Swap(&a[parent], &a[child]);
parent = child;
child = parent * 2 + 1;
}
}
void HeapSort(int* a, int n)
{
//建堆
for (int i = (n-2)/2; i >= 0 ; i--)
{
AdjustDown(a, n, i);
}
int new_n = n - 1;
while (new_n)
{
Swap(&a[new_n], &a[0]);
AdjustDown(a, new_n--, 0);
}
}
4.快速排序
快速排序的基本思想就是选择数据中的中位数,然后利用双指针或者三指针进行快速对比交换排序
- 时间复杂度:O(NlogN) ~O(NN)
- 空间复杂度:O(1)
//双指针法 horel
int Par1(int* a, int left, int right)
{
int key_i = left;
while (left < right)
{
while (left < right && a[right] >= a[key_i])
right--;
while (left < right && a[left] <= a[key_i])
left++;
Swap(&a[left], &a[right]);
}
Swap(&a[left], &a[key_i]);
return left;
}
//双指针前后
int Par2(int* a, int left, int right)
{
int key_i = left;
int pre = key_i;//尾随cur把大的往后甩
int cur = key_i + 1;//cur负责赵小
while (cur <= right)
{
if (a[cur] < a[key_i] && ++pre != cur)
Swap(&a[cur], &a[pre]);
cur++;
}
Swap(&a[key_i], &a[pre]);
return pre;
}
//处理重复数据的快排
void QucikSort_repeatdate(int* a, int left, int right)
{
if (left >= right)
return;
//随机选数
int randi = left + (rand() % (right - left));
if (randi != left)
{
Swap(&a[randi], &a[left]);//以左边做关键值
}
int begin = left;
int end = right;//保存 起始结点 和 尾结点
int keyi = a[left];
int cur = left + 1;
while (cur <= right)
{
if (a[cur] < keyi)
{
Swap(&a[cur], &a[left]);
left++;
cur++;
}
else if (a[cur] > keyi)
{
Swap(&a[cur], &a[right]);
right--;
}
else
cur++;
}
//所有相等的数据都在中间部位了
QucikSort(a, begin, left - 1);//递归左区间
QucikSort(a, right + 1, end);//递归右区间
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
int middle_i = Par2(a, left, right);
QuickSort(a, left, middle_i - 1);
QuickSort(a, middle_i + 1,right);
}
5.归并排序
归并递归的思想是,将所有元素分割到最小单位,当元素都是单个时,此时可以认为单个元素是有序的,然后进行壹壹归,之后进行贰贰归、肆肆归(2的倍数)。。。。以此类推最后将所有元素归并为有序。归并的整个过程是比较大小后进行尾插。归并排序之前写过点击归并排序即可。
- 时间复杂度:O(N*logN) )
- 空间复杂度:O(N)
6.计数排序(数据映射类排序)
计数排序对于数据范围集中的整形类数据排序速度很快,是一种映射类排序,但是排序出的数据并不是原始数据,只是对原始数据进行的一种复制排序。
//计数排序
void CountSort(int* a, int n)
{
int min = a[0];
int 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*)calloc(range,sizeof(int));
if (NULL == count)
{
perror("mlc fail\n");
exit(-1);
}
//统计数据出现次数
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;
}
}
}
7.选择排序和冒泡排序
选择排序只推荐用来浅浅的了解一下,选择排序性能其实很一般,跟冒泡排序一个等级。
void SelectSort(int* a, int n)
{
int begin = 0, end = n - 1;
while (begin < end)
{
int mini = begin, maxi = begin;
for (int i = begin + 1; i <= end; i++)
{
if (a[i] > a[maxi])//选出最小的
maxi = i;
if (a[i] < a[mini])//先出最大的
mini = i;
}
Swap(&a[begin], &a[mini]);
if (maxi == begin) maxi = mini;//修正maxi,避免begin就是最大值的情况。
Swap(&a[end], &a[maxi]);
++begin;
--end;
}
}
void BubbleSort(int* a, int n)
{
int flag = 1;
for (int i = 0; i < n-1; i++)
{
flag = 1; //-1是为了防止越界
for (size_t j = 0; j < n-i-1; j++)//不-1,第一趟就会越界,n-i(0) = n,第一趟最后比较就是n-1和n的数据比较,但是n位置就是越界了。
{
if (a[j] > a[j + 1])
{
Swap(&a[j], &a[j + 1]);
flag = 0;
}
}
if (1 == flag)
break;
}
}