算法的稳定性,我自己概括为:在一次排序过程中,如果出现两个相同的值,这两个相同值的相对位置不发生变化,那么他就是稳定的。比如一个数组a[5] = {1,4,3,4,1},对于这个数组,他排完序后第一个‘4’和第二个‘4’的相对位置不发生变化,就是稳定的。
首先定义一个数组,我定义是赋初值的,当然也可以循环输入,我的是降序排列。
一、冒泡排序
时间复杂度为O(n^2),稳定的排序算法。
本质是相邻两个数字进行比较,外层for循环用于控制比较多少次,内层for循环用于逐次比较出每一个最小值。
for(i = 0; i < 5-1; i++)//五个数比较四次(len-1)
{
for (j = 0;j < 5-1-i; j++)//len-1-i
{
if (a[j] > a[j+1])
{
tmp = a[j];
a[j] = a[j+1];
a[j+1] = tmp;
}
}
}
二.选择排序
时间复杂度为O(n^2),不稳定的排序算法。
选择排序是将一个元素与数组中的所有元素,进行对比,每次比较找出一个最值,j是控制排了多少次,然后将i控制的值a[i]与j控制的值a[j]进行比较,(内层)每次都比较到了最后一个。
int min_num = 0;
for (i = 0; i < 5-1; i++)//五个数比较四次(len-1)
{
min_num = i;
for (j = i+1; j < 5; j++)//一直要找到最后一位
{
if (a[j] < a[min_num])
{
min_num = j;
}
if (min_num != i)
{
tmp = a[min_num];
a[min_num] = a[i];
a[i] = tmp;
}//每次选择出来一个最小值
}
}
三、插入排序
时间复杂度为O(n^2),稳定的排序算法。
所谓插入,就是在一个有序的序列中插入一个记录,确保插入后的序列仍然有序。如果原序列有序,那么插入排序的算法的效率是最高的。
此代码,i表示插入多少趟,j表示要插入的位置。
//插入
for (i = 1; i < 5; i++)
{
tmp = a[i];//每次先保存a[i]的初值
//j-1>=0==>j>0
for (j = i; j>0 && tmp<a[j-1]; j--)//满足条件才进入此次循环
{
a[j] = a[j-1];//数据往后走,标号j往前走
}
a[j] = tmp;//这里的j可以到0
}
四、哈希排序
时间复杂度为O(logn)~ O(n^2),不稳定的排序算法。
哈希排序。本质就是将一个待排序列分成若干个子序列,然后再利用插入排序的算法,对其进行排序。
此处我封装了一个API,参数a代表传入的数组名,和传入的长度。
每次找一个中间值inc进行分割,将分割前后的序列作为新的子序列,再进行插入排序。
void ShellSort(int *a, int len)
{
int inc = 0;
int i = 0;
int j = 0;
for(inc = len/2; inc > 0; inc/=2)
{
for(j = inc; j < len; j+=inc)
{
int tmp = a[j];
for(i = j; a[i-inc] < tmp && i >= inc; i-=inc)
{
a[i] = a[i-inc];
}
a[i] = tmp;
}
}
}
五、快速排序
时间复杂度为O(logn),不稳定的排序算法。
每次选择一个基准值,经过一次快排之后,基准值的位置就是他自己在该序列中该有的位置,基准值左边全是比基准值小的序列,右边就是比基准值大的序列,第二次快排就是将左边或者右边的子序列再快排。然后递归去快排,直至每次快排都结束(传入的数组元素的头和尾相等)。
a:数组名 begin:数组第一个元素 end:数组的最后一个元素。
int QuilkSort(int *a, int begin, int end)
{
if (begin >= end)
{
return 0;
}
int i = begin;
int j = end;
int key = a[i];
while(i < j)//相等推出循环,一轮循环结束
{
while(i < j && a[j] >= key)
{
j--;
}
a[i] = a[j];//不合适就把后面不合适的值给前面
while(i < j && a[i] <= key)
{
i++;
}
a[j] = a[i];//不合适接把前面不合适的给后面
}
a[i] = key;//键值归位
QuilkSort(a, begin, i-1);//前半序
QuilkSort(a, i+1, end);//后半序
}
相比与其他算法,快排是效率最高的,同时我也认为是逻辑较为为复杂的,于此同时,系统库函数给我们提供了一个快速排序的函数接口,
void qsort(void* base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*));
功能: 使用快速排序例程进行排序
参数: 1 待排序数组,排序之后的结果仍放在这个数组中
2 数组中待排序元素数量
3 一个元素的占用空间大小
4 指向函数的指针,用于确定排序的顺序(需要用户自定义一个比较函数)
第四个参数是一个函数指针,就是用户自己定义如何去排序。
//升序
int compare(const void*arg1, const void*arg2)
{
const int *p1 = (const int *)arg1;
const int *p2 = (const int *)arg2;
return *p1-*p2;
}
//降序
int compare(const void*arg1, const void*arg2)
{
const int *p1 = (const int *)arg1;
const int *p2 = (const int *)arg2;
return *p2-*p1;
}
//调用
qsort(a,len,sizeof(a[0],compare));