三种基本排序方法(C语言实现)
·
三种基本排序(以升序为例)
1.冒泡排序
思想:每次相邻两个数比较,若升序,则将大的数放到后面,一次循环过后,就会将最大的数放在最后.
如图9 3 2 5 8 4 7 6是输入的待排序的数列,经过第一次排序,将最大的9放在最后,第二次排序,将剩下的2 3 5 4 7 6 8进行冒泡,将当前最大的8放在倒数第二的位置,以此类推
接下来上代码
#include <stdio.h>
int main(void)
{
int a[1001];
int n,i,j,t;
scanf("%d",&n);//n为要排序的数的个数
//输入要排序的数
for(i=0;i<n;++i)
scanf("%d",a+i);
//接下来进行排序
for(i=0;i<n-1;++i)//n个数,总共需要进行n-1次
{ //n-1个数排完,第一个数一定已经归位
//每次会将最大(升序)或最小(降序)放到最后面
for(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(j=0;j<n;++j)
printf("%-5d ",a[j]);
printf("\n\n");
}
return 0;
}
可见冒泡的时间复杂度是O(N²),可以对冒泡排序进行优化,若排序的过程中,序列已变为有序,则不会进行冒泡,所以之后的排序就不用进行了,这样的话,序列越是有序,则时间复杂度会趋于O(N),以下为改进后的代码
for(i=0;i<n-1;++i)//n个数,总共需要进行n-1次
{ //n-1个数排完,第一个数一定已经归位
//每次会将最大(升序)或最小(降序)放到最后面
int f=1;//这里设置一个开关变量
for(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;
f=0;
}
}
if(1==f)//f为1说明没进行过冒泡,说明序列有序
break;//若序列有序,则跳出排序即可
}
2.选择排序
思想:从第一个数开始,每次和后面剩余的数进行比较,若升序,则如果后边的数比当前数字小,进行交换,和后面的所有的数比较、交换后,就会将当前的最小值放在当前的位置
输入的序列为9 3 2 5 8 4 7 6进行一次排序后将最小的数放在了第一位(a[0]与它后面的所有数进行比较,若a[0]比后面的数大,进行交换)后面的也是这个道理
接下来上代码
#include <stdio.h>
int main(void)
{
int a[1001];
int n,i,j,t;
scanf("%d",&n);//n为要排序的数的个数
//输入需要排序的数
for(i=0;i<n;++i)
scanf("%d",a+i);
//接下来进行排序
for(i=0;i<n-1;++i)//因为每次需要和a[i]后面的数进行比较,所以到a[n-2](倒数第2个元素)就行
{
for(j=i+1;j<n;++j)//j从i后一个开始,a[i]与a[j]进行比较
{
if(a[i]>a[j])//a[i]为当前值,若是比后面的a[j]大,进行交换
{
t=a[i];
a[i]=a[j];
a[j]=t;
}
}//每排序一次,就会将a[i](包括a[i])之后的最小值放在a[i]的位置
for(j=0;j<n;++j)
printf("%-5d",a[j]);
printf("\n\n");
}
return 0;
}
可见,线则排序的时间复杂度也为O(N²),我们无法降低它的时间复杂度,但是也可进行优化,每次选择排序,都需要进行好多次的交换,这样也比较浪费资源,我们只需要用一个变量来存储最小值的下标(升序排序),最后进行交换,也可以达到目的,这样会节省很多时间,改进后代码如下
for(i=0;i<n-1;++i)
{
int k=i;//设置一个变量存储下标
for(j=i+1;j<n;++j)//遍历a[i]后的数
{
if(a[k]>a[j])
k=j;
}//执行过后,k会存储当前最小值的下标
//进行一次交换
t=a[k];
a[k]=a[i];
a[i]=t;
}
3.插入排序
思想:我们都玩过扑克牌,我们也会习惯性的把牌按一定的顺序排序,这和插入排序的思想极为相似
我们用扑克的方法解释,首先我们抽到第一张牌,将它放在第一位,我们排序是从第二次抽牌开始,第二次抽起一张牌3,它比9小,所以将9向后移一位然后把3放在9原来的位置.再次抽牌2,发现它应该再3的前面,所以将3和9向后移,把2放到3原来的位置... ... 如图,蓝色标明了顺序.
接下来上代码
#include <stdio.h>
int main(void)
{
int a[1001];
int i,j,t,n;
scanf("%d",&n);//输入要排序的数的个数
for(i=0;i<n;++i)//输入要排序的数
scanf("%d",a+i);
for(i=1;i<n;++i)
{
t=a[i];//将a[i]“拿在手中”
for(j=i-1;j>-1 && a[j]>t;j--)//和前面的牌比
{
//如果前面的"牌"比手中的"牌"大,则将"牌"向后移
a[j+1]=a[j];
}//跳出循环则表明了"手中的牌的位置找到了"
a[j+1]=t;//将"牌"插入
for(j=0;j<n;++j)
printf("%-5d",a[j]);
printf("\n\n");
}
return 0;
}
时间复杂度O(N²),若数列基本有序,则时间复杂度会趋于O(N)
谢谢大家很耐心的看完这篇博客,希望对加大有所帮助.本人纯手打,转载请注明出处,谢谢.
后续更新
插入排序的递归实现:
void Insert_sort(int p[],int left,int right){
if(left>=right)
return ;
Insert_sort(p,left,right-1);
int temp;
int i;
temp=p[right];
for(i=right;i>left && p[i-1]>temp;--i)
p[i]=p[i-1];
p[i]=temp;
for(int j=left;j<right+1;++j)
printf("%5d",p[j]);
printf("\n");
return ;
}
对于插入排序优化的思考:
对于插入排序,最差情况下的时间复杂度为O(N²),若寻找插入点的位置时,我们不使用线性的依次寻找,而使用二分法,二分法查找的时间复杂度为O(lgN)(这里的lg是以2为底的)。这样,可以将插入排序的时间复杂度将为O(N*lgN)。这样是否合理呢?
答案是不能,因为找到插入点后,仍需要将插入点后面的元素向后移一位,这个过程的时间复杂度是O(N),这样的话,二分法查找插入点其实是多余的。
阅读全文
AI总结
更多推荐
相关推荐
查看更多
A2A

谷歌开源首个标准智能体交互协议Agent2Agent Protocol(A2A)
adk-python

一款开源、代码优先的Python工具包,用于构建、评估和部署灵活可控的复杂 AI agents
Second-Me

开源 AI 身份系统,通过本地训练和部署,模仿用户思维和学习风格,创建专属AI替身,保护隐私安全。
目录
所有评论(0)