1.插入排序
插入排序的基本思路:一串无序的数据,第一个数据本身一定是有序的,直接判断第二个数据,如果第二个数据比第一个数据大,判断第三个,如果小,将第一个数据保存到第二个数据的位置,将第二个位置本来的数据放在第一个位置.
对每一个数据都进行这样的比较就能得到一组有序的数
void InsertSort(int* array,int size)
{
for (int i = 1; i < size; i++)
{
//待排序元素的前一个下标
int a = i - 1;
//待排元素的值
int temp = array[i];
while (a>=0&&temp < array[a])
{
array[a + 1] = array[a];
a--;
}
array[a + 1] = temp;
}
}
插入排序的应用场景:应用于序列接近有序,且数据量小的时候
如果数据太乱,插入排序也能排,但是效率底
数据量大的情况下,不能使用插入排序,因为插入排序是for循环嵌套,栈容易溢出
稳定性:稳定(因为不存在元素之间交换是隔着元素交换的,即只有相邻元素交换才是稳定的)
时间复杂度O(N^2)
空间复杂度O(1)
2.希尔排序
针对插入排序的局限进行了改进(让数据量变小或者让数据接近有序就可以使用插入排序)
假设将一组数据分三组,分组方法为,元素下标对三求余相等的数据是一组.例如下标是0,3,6的数据在一组,1,4,7下标的数据在一组.
分组之后分别对每一组进行插入排序
void ShellSort(int* array,int size)
{
int sign = size/3-1;
while (sign)
{
for (int i = sign; i < size; i++)
{
int a = i - sign;
int temp = array[i];
while (a >= 0 && temp < array[a])
{
array[a + sign] = array[a];
a-=sign;
}
array[a + sign] = temp;
}
sign--;
}
}
sign即是外层循环的此数,也标记第一组的第二个数据4,依次往后是第二组的第二个数据,第三组的第二个数据...往后依次类推
sign的取值有很多种,不用只局限于一种,size/3-1比较常用
里层的两个循环和插入排序的意义是一样的,区别在于,插入排序拍一组数据,希尔排序排多组数据,所以为了定位到本组内的数据需要减去组数找到本组的前一个元素,或者加组数找到本组的后一个元素.
希尔排序不稳定,因为存在跨元素交换或覆盖的情况
注意:希尔排序用于数据量比较大的情况,如果数据量小.不建议用希尔.因为希尔排序要注意分组的个数,因为用sign=size/3-1的方法取sign依赖于size,如果size较小,最外层可能循环次数太少,不足以完成排序,甚至一次也执行不了.
3.选择排序
选择排序是每次将数组遍历一遍,标记最大的数和最后一个数进行交换,则最后一个就已经排好了,下一次循环在数组大小为size-1里找最大的最后一个数进行交换.
void SelectSort1(int* array,int size)
{
int a = size;
for (int i = 1; i < a; i++)
{
int maxpop = 0;
for(int j=1;j<size;j++)
{
if (array[j] > array[maxpop])
{
maxpop = j;
}
}
Swap(&array[maxpop], &array[size-1]);
size--;
}
}
对于选择排序的优化,既然内层循环一次可以找到一个最大的,那么同时也可以找到一个最小的,内层循环循环一次就可以排好两个数据:
选择排序的优化
void SelectSort2(int* array, int size)
{
int begin = 0;
int end = size - 1;
while (begin < end)
{
int minpop = begin;
int maxpop = end;
for (int i = begin+1; i <= end; i++)
{
if (array[i] < array[minpop])
{
minpop = i;
}
if (array[i] > array[maxpop])
{
maxpop = i;
}
}
Swap(&array[minpop], &array[begin]);
if (maxpop == begin)
{
maxpop = minpop;
}
Swap(&array[maxpop], &array[end]);
begin++;
end--;
}
}
4.冒泡排序(升序)
如果后一个数据小于他之前的数据就交换这两个相邻的数据,一趟循环之后就会得到最后一个数据是最大的,依次再排其他数据
void BollleSort(int* array,int size)
{
for (int i = 0; i < size - 1; i++)
{
int sign = 0;
for (int j = 0; j < size - i-1; j++)
{
if (array[j] > array[j + 1])
{
Swap(&array[j], &array[j + 1]);
sign = 1;
}
}
if (sign == 0)
{
return;
}
}
}
如果循环没有循环到最后数据已经是有序的了,内层for循环里的if语句一次都没有执行,说明数据已经有序,sign一直是0;直接返回,不进行多余的比较