写在前面:
因为网络上有很多篇讲排序算法的,所以这里就不详细讲了,只作为参考和自己查阅
当然了,虽然篇幅也会短很多,但部分重点和要点还在
八种排序算法分别是:
①选择排序; ②冒泡排序; ③插入排序; ④快速排序;
⑤归并排序; ⑥计数排序; ⑦希尔排序; ⑧堆排序;(蓝色为不稳定排序)
一,选择排序:
特点:应该是90%的人学C语言,所会的第一个排序
步骤:每次选择后n-i个数字中最小的和当前第i位交换
复杂度Θ(n²),O(n²)
void Select_sort(int *a, int n)
{
int i, j, now, id;
for(i=1;i<=n;i++)
{
id = i;
now = a[i];
for(j=i+1;j<=n;j++)
{
if(a[j]
二,冒泡排序:
特点:应该是剩下10%的人学C语言,所会的第一个排序
步骤:①暴力枚举相邻的两个数,如果逆序就把它们交换
②一趟下来最大的数肯定在第n位,那么对前n-1位再来一趟……以此类推直到有序
复杂度Θ(n²),O(n²)
void Bubble_sort(int *a, int n)
{
int i, j;
for(i=1;i<=n;i++)
{
for(j=1;j<=n-i;j++)
{
if(a[j+1]
三,插入排序:
特点:很像玩扑克牌时,每摸一张牌,就把这张牌插入一个合适的位置,使得手牌保持有序
步骤:就是模拟上述过程
复杂度Θ(n²),O(n²)
void Insert_sort(int *a, int n)
{
int i, j, temp;
for(i=2;i<=n;i++)
{
if(a[i]>=a[i-1])
continue;
temp = a[i];
for(j=i-1;a[j]>temp&&j>=1;j--)
a[j+1] = a[j];
a[j+1] = temp;
}
}
四,快速排序:
特点:非常著名的排序算法,在所有交换类排序中,它是最快的!
步骤:①在无序的数组中选择一个数x作为基数
②把比x小的数扔到x左边,比x大的数字扔到x右边(这个步骤当然是线性的,处理方法略)
③这样x会把整个数组分成两个部分,对于两个部分重复操作直到有序
注意:一般来讲都是选择当前第一个数作为基数,如果每次选的基数都恰好是当前最大/最小的,那么复杂度会达到n²,为了防止上述过程发生,可以有很多优化方法,例如随机选择三个数,将其中第二大的数作为基数
复杂度Θ(nlogn),O(n²)
void Quick_sort(int *a, int L, int R)
{
int i, j, x;
if(L>=R)
return;
i = L, j = R;
x = a[i];
while(i=x) /*两个while循环不能交换*/
j--;
while(i
五,归并排序:
特点:分治,核心是将两个有序的数组合并只需要线性的复杂度
步骤:对于样例 1 5 2 8 9 5 4 6;① 1 5 | 2 8 | 5 9 | 4 6
② 1 2 5 8 | 4 5 6 9;③ 1 2 4 5 5 6 8 9 完成排序
复杂度Θ(nlogn),O(nlogn)
缺点:需要多开一倍空间(一个数组搞不定)
void Merge_sort(int *a, int *b, int L, int R)
{
int i, j, m, p;
if(L==R)
return;
m = (L+R)/2;
Merge_sort(a, b, L, m);
Merge_sort(a, b, m+1, R);
i = L, j = m+1, p = L-1;
while(i<=m || j<=R)
{
if(j>R || a[i]
六,计数排序(桶排序):
特点:非常简单的排序,对于数据相对集中的数列才能使用这种方法
步骤:①计算数列的最大值Max和最小值Min
②申请一个大小为Max-Min的数组,遍历一遍统计b[x-Min]表示数字x出现次数
②再遍历一遍b[]把所有数字列出来(有序还原)
复杂度Θ(n),O(n)
void Count_sort(int *a, int n)
{
int *b, i, p, Min, Max;
Min = Max = a[1];
for(i=2;i<=n;i++)
{
Min = min(Min, a[i]);
Max = max(Max, a[i]);
}
b = new int[Max-Min+1];
memset(b, 0, (Max-Min+1)*sizeof(int));
for(i=1;i<=n;i++)
b[a[i]-Min]++;
p = 0;
for(i=0;i<=Max-Min;i++)
{
while(b[i]--)
a[++p] = Min+i;
}
delete []b;
b = NULL;
}
七,希尔排序(缩小增量排序、Shell排序):
特点:对于元素基本有序的序列,效率极高
步骤:①设数列有14个元素,设k = 14/2 = 7,对a[1], a[8]进行插入排序,a[2], a[9]进行插入排序,a[3], a[10]进行插入排序……
②再次设k = 7/2 = 3,对a[1], a[4], a[7], a[10], a[13]进行插入排序,a[2], a[5], a[8], a[11], a[14]进行插入排序……
②再次设k = 3/2 = 1,对a[1], a[2], …, a[14]进行插入排序
复杂度Θ(n^1.3),O(n²)
void Shell_sort(int *a, int n)
{
int i, j, z, temp;
for(z=n/2;z>=1;z/=2) //z为增量,这里可以用其它的增量数组代替
{
for(i=z+1;i<=n;i++)
{
if(a[i]>=a[i-z])
continue;
temp = a[i];
for(j=i-z;a[j]>temp&&j>=1;j-=z)
a[j+z] = a[j];
a[j+z] = temp;
}
}
}
八,堆排序(二叉排序):
特点:最复杂的一个排序,详细讲解请戳这里
步骤:①构造初始堆,将给定无序序列构造成一个大顶堆(升序采用大顶堆,降序采用小顶堆)
②将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端
③重新调整堆结构,继续执行步骤②直到有序
复杂度Θ(nlogn),O(nlogn)
void Adjust(int *a, int p, int n) //调整节点p
{
int x, i;
x = a[p];
for(i=2*p;i<=n;i=i*2) //从p点的两个孩子开始
{
if(i+1<=n && a[i+1]>a[i]) //寻找两个孩子中更大的那个
i++;
if(a[i]>x) //如果当前节点比父亲大(不满足大顶堆性质)
{
a[p] = a[i]; //交换这个节点与父亲的值
p = i;
}
else
break;
}
a[p] = x;
}
void Heap_sort(int *a, int n) //注意我的数组下标是从1开始的!
{
int i;
for(i=n/2;i>=1;i--)
Adjust(a, i, n);
for(i=n;i>=2;i--)
{
swap(a[1], a[i]); //堆顶和末尾交换
Adjust(a, 1, i-1);
}
}
End