排序算法
Posted cimuhuashuimu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法相关的知识,希望对你有一定的参考价值。
目前不断更新中
每种算法的思想以及复杂度都在描述代码上方,算法描述图有时间会补上
template<class T>
class sort {
public :
//插入排序:
void InsertSort(T r[], int n) {
//思想:将数列分为有序和无序,从前往后逐个增加有序数列个数,每次将无序数列第一个划入有序数列最后一个,在有序数列进行排序
//最坏情况比较Σi[2,n]换位Σ(i+1)[2,n] n(n+1)/2-1+n(n+1)/2-3 = n(n+1)-4
//最好情况求和(n-1)
//平均时间 (n(n+1)-4)+(n-1)/2 ≈ n^2 空间 1 稳定排序
//适合小于千规模排序 基本有序数列
for (int i = 2; i <= n; i++) { //逐个将无序序列第一个元素加入有序序列,初始默认第一个已在有序序列
if (r[i] < r[i - 1]) {
r[0] = r[i];
int j ;
for (j = i-1; r[0] < r[j]; j--) { //将有序序列新加入的元素进行排序,使用哨兵优化
r[j + 1] = r[j];
}
r[j + 1] = r[0];
}
}
}
void ShellInsertSort(T r[], int n) {
//思想:将数列分为几组,每组每个元素间隔n/2,对每组进行简单插入排序,再将间隔变为n/4 ……,直到间隔为1即只有一组
//时间复杂度不定 在n^2与nlog2 3 之间(大概为n^1.3) 空间 1 不稳定(相同的关键码会变换位置)
//比简单插入排序更优
for (int d = n / 2; d >= 1; d = d / 2) { //对距离d=n/2进行分组,(1,n/2+1,n/2*2+1,……),(2,n/2+2,……),最后为1,2,……,n
for (int i = d + 1; i <= n; i++) {
//对分好组的直接插入排序,默认每个分组第一个在有序数列,从第一个分组的第二元素开始逐个加入第一分组有序数列,第二个分组第二元素……
if (r[i] < r[i - d]) {
r[0] = r[i];
int j;
for ( j = i - d; j > 0 && r[0] < r[j]; j = j - d) {
r[j + d] = r[j];
}
r[j + d] = r[0];
}
}
}
}
//交换排序:
void BubbleSort(T r[], int n) {
//思想:将数列分为有序和无序,有序数列为从后往前逐个增加,在无序中遍历一趟找到最大加入到新增加的有序数列位置
//最好情况 比较 (n-1)n/2 最坏情况 比较(n-1)n/2 换位 3(n-1)n/2
//平均时间 5(n-1)n/4 ≈ n^2 空间 1 稳定
for (int i = 1; i < n; i++) { //逐步增加有序区的个数,增加到n-1个最后一个自动到有序区
for (int j = 1; j <= n - i; j++) { // 交换一趟无序区,将无序区最大加到新增的有序区n-i+1位置(有序区从后往前增加)
if (r[j] > r[j + 1]) {
r[0] = r[j];
r[j] = r[j + 1];
r[j + 1] = r[0];
}
}
}
}
void ImprovBubbleSort(T r[], int n) {
//思想:在冒泡排序基础上,用pos来指定进入有序区前最后一个交换的位置,来避免无序区的有序部分重复比较
//在每次对无序区交换一趟已经对部分位置进行交换排序,如果每次pos为无序最后一个则与冒泡相同,如果出现不是无序最后一个,那么pos之后的都可以直接划入有序区
//最好情况 比较n-1 最坏情况 比较(n-1)n/2 交换3(n-1)n/2
//平均时间复杂度 (n-1)(2n+1)/2 ≈ n^2 空间复杂度 1 稳定
int pos = n;
while (pos != 0) { //pos及之前的部分为无序区
int bound = pos;
pos = 0;
for (int i = 1; i < bound; i++) { // 交换一趟无序区,bound位置是每次新增的有序区部分
if (r[i] > r[i + 1]) {
r[0] = r[i];
r[i] = r[i + 1];
r[i + 1] = r[0];
pos = i; //指向发生交换的位置
}
}
}
}
//快速排序:
//思想:将无序数列进行分块,找到首个元素在有序数列中位置,然后分得左无序数列和右无序数列,再找左和右数列的首个元素的位置,以此类推
//每次得到的左数列都小于等于轴值pivot,右边大于等于pivot,所以最终将获得整个有序数列
//最好的情况,每次分区的元素的左右分区个数相等,此时栈层数为log2 n,定位元素时间复杂度为n,总复杂度为nlog2 n
//最坏情况,正序或逆序,递归栈层数为n-1,定位元素时间复杂度为n,总复杂度为n(n-1) ≈ n^2
//平均来说复杂度为nlog2 n 栈层数为log2 n 不稳定
int Partion(T r[], int i, int j) { //分区作用,找到数组首个元素在有序数列中的位置
//将第一个元素定为pivot,先从后往前比较,如果遇到小的就将值赋给前面的比较位,然后前比较位从前往后遇到大的给后比较位(往返),最后pivot给i=j位
int pivot = r[i];
while (i < j) {
while (i<j && r[j]>=pivot) {
j--;
}
r[i] = r[j];
while (j > i&& r[i] <= pivot) {
i++;
}
r[j] = r[i];
}
r[i] = pivot; //哨兵优化交换次数
return i;
}
void Qsort(T r[], int i, int j) { // 利用分区函数快速排序
if (i < j) {
int pivotloc = Partion(r, i, j);//找到每次的中间位,进行递归
Qsort(r, i, pivotloc - 1);
Qsort(r, pivotloc + 1, j);
}
}
//选择排序:
};
以上是关于排序算法的主要内容,如果未能解决你的问题,请参考以下文章