目录
插入排序
思想
数组下标end,从0开始到数组总数n-1,依次遍历数组中的数字。
以end为分界线,0-end+1为有序,end+2-n为无序
注意事项
记得保留第end+1个数字的值,因为end在不断改变,end+1所指代的值也会改变。要记住的是,插入排序是在0--end+1个数字中给end+1找到一个合适的位置。
代码
void InsertSort(int* a, int n) {
//遍历第一个到倒数第一的前一个数字
for(int i=0;i<n-1;i++)
{
int end = i;
//默认0-end有序,把end+1插入进去
//记录下数据
int tmp = a[end + 1];
//遍历end前的所有数据,直到有序或者到头
while (end >= 0) {
//为什么是end>=0
//最坏情况下tmp可能是0-end中最小的那个数
if (a[end] > tmp) {
a[end + 1] = a[end];
end--;
}
else {
break;
}
}
//更新tmp
a[end + 1] = tmp;
}
}
复杂度计算
最坏的情况
外层for循环走n-1次,内层while循环走1+2+3+…+n-1次
总共为O(N^2)
最好的情况
不用调O(N)
希尔排序
思想
希尔排序是插入排序的变形,插入排序的排序间隔是不变的,也就是从0至n-1每个数都遍历,而希尔排序以gap为间隔,将n个数字分组,每个组有序,整个数组也就有序了。
gap的值也是在不断缩小的
gap越大,大的数据可以越快跳到后面,gap越小,跳的越慢越接近有序
其实就是一个调整gap的循环套上一个gap为间隔的插入循环
注意事项
gap值的确定:
gap==1时为插入排序,gap>1为希尔排序
代码
void ShellSort(int* a, int n) {
//原理就是将0-gap的数字都遍历一遍,不断调整gap的大小
//gap越大,大的数据可以越快跳到后面
//gap越小,跳的越慢越接近有序
//给gap赋值
int gap = n;
while (gap > 1) {
//调整gap
gap = gap / 2;
//这是以gap为间距的插入排序
for (int i = 0; i < n-gap; i ++) {
int end = i;
int tmp = a[end + gap];
while (end >= 0) {
if (a[end] > tmp) {
a[end + gap] = a[end];
end-=gap;
}
else {
break;
}
}
a[end + gap] = tmp;
}
}
}
复杂度计算
选择排序
思想
begin、end为数组的下标。begin代表起始位置,end代表最后位置
选出最小的数字放在begin位置,选出最大的数字放在end位置
注意事项
最大数字在第一位时需要调整
代码
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++) {
//记录从begin+1至end的最小值和最大值
if (a[i] > a[maxi]) {
maxi = i;
}
if (a[i] < a[mini]) {
mini = i;
}
}
//交换最小值
Swap(&a[begin], &a[mini]);
//如果最大值在首位
if (maxi == begin) {
maxi = mini;
}
//交换最大值
Swap(&a[end], &a[maxi]);
++begin;
--end;
}
}
复杂度计算
n/2次循环
第一次循环,第一次循环…… 第n/2次循环,
n-1 +n-3+ …… +1
O(N^2)
冒泡排序
思想
与希尔排序类似,冒泡排序最后面的数字是有序的,以n-i为分界线,0- n-i为无序,n-i -n为有序
第一个for循环遍历所有的数字
第二个for循环遍历从1至n-i个数字,每次循环将数字与它前面的数相比较
代码
void BubbleSort(int* a, int n)
{
for (int j = 0; j < n; ++j)
{
int exchange = 0;
for (int i = 1; i < n - j; ++i)
{
if (a[i - 1] > a[i])
{
Swap(&a[i - 1], &a[i]);
exchange = 1;
}
}
if (exchange == 0)
{
break;
}
}
}
复杂度计算
O(N^2)
快速排序
思想
设定一个key,通常是数组的第一个或者是最后一个。作为比较的依据。
两个指针 left 寻找比key大,right寻找比key小的数字
其中一个找到即停下
直到两个都找到才进行交换
在left--right中交换过之后,将最后两个指针相遇的地方同key 交换
最后达到的结果为key左边的数都比key小,key右边的数都比key大
在递归中不断改变key,
注意事项
两个指针相遇的地方同key 交换
当key是起始位置第一个数时,right先走,相遇位置的数字一定比key小吗?
当left与right停下有两种情况
1、left 停下(表示已经找到比key大的数,且已经交换过,此时left的数比key小),right走,right遇到left(此时right没有找到比key小的数字,但是已经不满足条件left<right了所以终止循环),相遇位置的数字比key小
2、right停下(表示已经找到比key小的数),left走,left遇到right,相遇位置的数字比key小
left与right谁先走谁后走也是很重要滴
代码
int PartSort(int* a, int left, int right)
{
int keyi = left;
while (left < right)
{
// R找小
//两个条件一个不能少,必须带上=号
while (left < right && a[right] >= a[keyi])
{
--right;
}
// L找大
while (left < right && a[left] <= a[keyi])
{
++left;
}
if (left < right)
Swap(&a[left], &a[right]);
}
int meeti = left;
Swap(&a[meeti], &a[keyi]);
return meeti;
}
void QuickSort(int* a, int begin, int end)
{
if (begin >= end)
{
return;
}
int keyi = PartSort(a, begin, end);
//[begin, keyi-1] keyi [keyi+1, end]
QuickSort(a, begin, keyi - 1);
QuickSort(a, keyi + 1, end);
}
复杂度计算
O(logN)