七种排序算法分析和C源代码的实现
选择排序
首先初始化数组首元素,外循环依次遍历排序数组,内循环再遍历数组,直至尾元素,若遇到需要交换的元素则进行交换,待双循环遍历结束,得到已排序好的数组。
时间复杂度:O(n2)
最坏情况:O(n2)
最好情况:O(n2)
稳定性:稳定
适用于n较小时
#include <stdio.h>
#define MAX 50000
int n, a[MAX], t;
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
for(int i=1; i<n; i++)
{
for(int j=i+1; j<=n; j++)
{
if (a[i] > a[j]) {
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
}
for(int i=1; i<=n; i++)
printf("%d ", a[i]);
return 0;
}
冒泡排序
依次比较相邻两元素,若前一元素大于后一元素则交换之,直至最后一个元素即为最大;然后重新从首元素开始重复同样的操作,直至倒数第二个元素即为次大元素;待循环结束得到已排序好的集合。
时间复杂度:O(n2)
最坏情况:O(n2)
最好情况:O(n)
稳定性:稳定
适用于n较小时
#include <stdio.h>
#define MAX 1000001
int a[MAX], n, t;
int main()
{
scanf("%d", &n);
for(int i=0; i<n; i++)
scanf("%d", &a[i]);
for(int i=0; i<n; i++)
{
for(int j=0; j<n-i-1; j++)
{
if(a[j] > a[j+1]) {
t=a[j]; a[j]=a[j+1]; a[j+1]=t;
}
}
}
for(int i=0; i<n; i++)
printf("%d ", a[i]);
return 0;
}
插入排序
数列前面部分看为有序,依次将后面的无序数列元素插入到前面的有序数列中,初始状态有序数列仅有一个元素,即首元素。在将无序数列元素插入有序数列的过程中,采用了逆序遍历有序数列,相较于顺序遍历会稍显繁琐,但当数列本身已近排序状态效率会更高。
时间复杂度:O(n2)
最坏情况:O(n2)
最好情况:O(n)
稳定性:稳定
适用于n较小时
#include <stdio.h>
#define MAX 100001
int n, a[MAX], t, j;
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; i++)
scanf("%d", &a[i]);
for(int i=1; i<=n; i++)
{
t = a[i];
for(j=i-1; j>=1; j--)
{
if (t < a[j]) {
a[j+1] = a[j];
}
else break;
}
a[j+1] = t;
}
for(int i=1; i<=n; i++)
printf("%d ", a[i]);
return 0;
}
希尔排序
插入排序的改进版。为了减少数据的移动次数,在初始序列较大时取较大的步长,通常取序列长度的一半,此时只有两个元素比较,交换一次;之后步长依次减半直至步长为1,即为插入排序,由于此时序列已接近有序,故插入元素时数据移动的次数会相对较少,效率得到了提高。
时间复杂度:O(n3/2)
最坏情况:O(n2)
最好情况:O(n)
稳定性:不稳定
#include <stdio.h>
#define MAX 500000
int n, a[MAX], t;
int main()
{
int t, k;
scanf("%d", &n);
for(int i=0; i<n; i++)
scanf("%d", &a[i]);
for(int i=n/2; i>0; i/=2)
{
for(int j=i; j<n; j++)
{
k = j;
t = a[j];
if (a[k] < a[k-i]) {
while (k-i>=0&&t < a[k-i]) {
a[k] = a[k-i];
k -= i;
}
a[k] = t;
}
}
}
for(int i=0; i<n; i++)
printf("%d ", a[i]);
return 0;
}
桶排序(基数排序)
桶排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间(桶)中。作为一种线性时间复杂度的排序,桶排序要求输入的数据必须是有确定范围的整数。
时间复杂度:O(d(r+n))
最坏情况:O(d(r+n))
最好情况:O(d(r+rd))
稳定性:稳定
#include <stdio.h>
#define MAX 100000
int a[MAX]={0}, n, t;
int main()
{
scanf("%d", &n);
for(int i=1; i<=n; i++)
{
scanf("%d", &t);
a[t]++;
}
for(int i=0; i<=10000; i++)
for(int j=1; j<=a[i]; j++)
printf("%d ", i);
return 0;
}
快速排序
选一基准元素,依次将剩余元素中小于该基准元素的值放置其左侧,大于等于该基准元素的值放置其右侧;然后,递归其左右两侧的集合进行相同的操作,快速排序是排序算法运用最广的算法。
时间复杂度:O(nlog2n)
最坏情况:O(n2)
最好情况:O(nlog2n)
稳定性:不稳定
适用于n较大时
#include <stdio.h>
int n, a[100001], k;
void qs(int l, int r)
{
int i, j, t, temp;
if (l > r) return ;
temp = a[l];
i = l;
j = r;
while (i != j)
{
while(a[j] <= temp && i<j)
j--;
while(a[i] >= temp && i<j)
i++;
if (i < j) {
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
a[l] = a[i];
a[i] = temp;
qs(l, i-1);
qs(i+1, r);
}
int main()
{
int i, j, t;
scanf("%d", &n);
for( i=1; i<=n; i++)
scanf("%d", &a[i]);
qs(1, n);
for( i=1; i<=n; i++)
printf("%d ", a[i]);
return 0;
}
堆排序
堆排序的思想借助于二叉堆中的最大堆得以实现。首先,将待排序数列抽象为二叉树,并构造出最大堆(或者最小堆);然后,依次将最大元素(即根节点元素)与待排序数列的最后一个元素交换(即二叉树最深层最右边的叶子结点元素);每次遍历,刷新最后一个元素的位置(自减1),直至其与首元素相交,即完成排序。
时间复杂度:O(nlog2n)
最坏情况:O(nlog2n)
最好情况:O(nlog2n)
稳定性:不稳定
适用于n较大时
#include <stdio.h>
#define MAX 500000
int s[MAX], n, num, k;
void swap(int x, int y)
{
int t;
t = s[x]; s[x] = s[y]; s[y] = t;
}
void shiftdown(int x)
{
int t, book = 0;
while (x*2 <= n&&book == 0) {
if (s[x] > s[x*2]) {
t = x*2;
}
else t = x;
if (x*2+1 <= n) {
if (s[x*2+1] < s[t]) {
t = x*2+1;
}
}
if (x != t) {
swap(x, t);
x = t;
}
else book = 1;
}
}
void create()
{
for(int i=n/2; i>=1; i--)
{
shiftdown(i);
}
}
void heapsort()
{
while(n > 0) {
swap(1, n);
n--;
shiftdown(1);
}
}
int main()
{
scanf("%d", &num);
n = num;
for(int i=1; i<=n; i++)
scanf("%d", &s[i]);
create();
heapsort();
for(int i=num; i>0; i--)
printf("%d ", s[i]);
return 0;
}
感谢Jamest博主的参考博客链接