博客主页: 小羊失眠啦.
系列专栏:《C语言》 《数据结构》 《Linux》《Cpolar》
❤️感谢大家点赞收藏⭐评论✍️
排序:所谓排序就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。排序算法,就是如何使得记录按照要求排列的方法。
稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。
排序算法分为比较类排序和非比较类排序,如下图所示:
较大(升序)或较小(降序)的记录向后移动
。如此循环,大/小的记录会慢慢“浮”到序列的后端,整个过程就像是冒泡一样,顾称之为冒泡排序。可以看出,对于上面具有5个元素的无序数组,我们通过4趟的冒泡后就将其变为有序数组,每一趟冒泡后都可以使最大的数沉底。
内层循环控制当前趟的数据交换,外层循环控制冒泡排序的趟数
。for (int i = 0; i < n - 1; i++) //外层循环,N-1趟
{
;
}
每趟的比较次数随着趟数的增加呈递减趋势,初始为N-1次
。for (int i = 0; i < n - 1; i++) //外层循环,N-1趟
{
for (int j = 0; j < n - 1 - i; j++) //内层循环,次数随趟数增加而递减,初始为N-1
{
;
}
}
void swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
void BubblingSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++) //外层循环,N-1趟
{
for (int j = 0; j < n - 1 - i; j++) //内层循环,次数随趟数增加而递减,初始为N-1
{
if (a[j] > a[j + 1]) //升序排列,较大的往后移
{
swap(&a[j], &a[j + 1]); //交换
}
}
}
}
对于情境1,我们只需一趟冒泡即可让数组有序,而如果按照上面的代码,我们依旧要进行4趟的冒泡,即有三趟是无效的。
而情境2就更夸张了,数组已经有序,我们却傻乎乎的做了4趟无效冒泡。无疑是非常浪费时间的。
考虑到这些情况,我们提出了优化方案:
在每趟结束后判断一下当前趟是否发生了元素交换
,如果没有,则说明序列已经有序了,及时止损,反之继续。优化后的代码如下:void swap(int* x, int* y) { int tmp = *x; *x = *y; *y = tmp; } void BubblingSort(int* a, int n) { for (int i = 0; i < n - 1; i++) //外层循环,N-1趟 { int flag = 0; for (int j = 0; j < n - 1 - i; j++) //内层循环,次数随趟数增加而递减,初始为N-1 { if (a[j] > a[j + 1]) //升序排列,较大的往后移 { swap(&a[j], &a[j + 1]); //交换 flag = 1; } } if (flag == 0) break; } }
注意:数组中除了第一个元素(默认有序),其余所有元素都看作待插入数据。
end
,则第一个待插入元素的下标为 end+1
,记作 tmptmp < a[end]
,就将 a[end] 向后移动,end–,再去找下一位进行比较tmp > a[end]
或者 end < 0
,将 tmp 插入到 end+1 的位置void InsertSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)
{
int end = i;
int tmp = a[end + 1];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + 1] = a[end];
}
else
{
break;
}
--end;
}
a[end + 1] = tmp;
}
}
思想:
先选定一个整数,把待排序文件中所有记录分成个组,所有距离为3的数据分在同一组内,并对每一组内的数据进行排序。然后,重复上述分组和排序的工作。当距离=1时,所有数据在统一组内排好序。
希尔排序分为两步:
预排序
直接插入排序
当元素集合越接近有序,直接插入排序的效率很高,希尔排序就是通过预排序使元素集合接近有序,再进行直接插入排序,这样大大提高了效率。
gap
作为间距gap
的数据分为一组,分成 gap 组gap==1
时,数据进行直接插入排序,实现排序void ShellSort(int* a, int n)
{
int gap = n;
while (gap > 1)
{
gap = gap / 3 + 1;
for (int i = 0; i < n - gap; i++)
{
int end = i;
int tmp = a[end + gap];
while (end >= 0)
{
if (tmp < a[end])
{
a[end + gap] = a[end];
end -= gap;
}
else
{
break;
}
}
a[end + gap] = tmp;
}
}
}
当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。
内层循环遍历序列找出最大/最小值,外层循环控制选择的次数
。for (int i = 0; i < n-1; i++) //外层循环,共要选择n-1次
{
;
}
for (int i = 0; i < n-1; i++) //外层循环,共选择n-1次
{
for (int j = i + 1; j < n; j++) //内层循环,起始位置开始向后进行比较,选最小值
{
;
}
}
void swap(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
void SelectSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++) //外层循环,共选择n-1次
{
int mini = i; //记录最小值的下标,初始为第一个数下标
for (int j = i + 1; j < n; j++) //内层循环,起始位置开始向后进行比较,选最小值
{
if (a[mini] > a[j]) //比最小值小,交换下标
{
mini = j;
}
}
swap(&a[mini], &a[i]); //将最小值与起始位置的数据互换
}
}
我们发现,在第一趟交换中,黑5被交换到了红5后面,在整个排序结束后,黑5依然在红5的后方,与最开始的顺序不一致。由此我们可以得出,选择排序是不稳定的排序。
本次的内容到这里就结束啦。希望大家阅读完可以有所收获,同时也感谢各位铁汁们的支持。文章有任何问题可以在评论区留言,小羊一定认真修改,写出更好的文章~~