排序算法(一)(十分基础版)
冒泡排序
**基本思想:两个数比较大小,较大的数下沉,较小的数冒起来。** 1.比较相邻的两个数据,如果第二个数小,就交换位置。 2.从后向前两两比较,一直到比较最前两个数据。最终最小数被交换到起始的位置,这样第一个最小数的位置就排好了。 3.继续重复上述过程,依次将第2.3...n-1个最小数排好位置。 |
平均时间复杂度:O(n2)
c语言代码实现
#include<stdio.h>
int main()
{
int a[1000];
int i;
int n;
int temp=0;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
for(i=0;i<n;i++)
{
for(int j=n-1;j>0;j--)
{
if(a[j]<a[j-1])
{
temp=a[j];
a[j]=a[j-1];
a[j-1]=temp;
}
}
}
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
return 0;
}
运行结果
优化:
针对问题:
数据的顺序排好之后,冒泡算法仍然会继续进行下一轮的比较,直到n-1次,后面的比较没有意义的。
方案:
设置标志位flag,如果发生了交换flag设置为true;如果没有交换就设置为false。
这样当一轮比较结束后如果flag仍为false,即:这一轮没有发生交换,说明数据的顺序已经排好,没有必要继续进行下去。
代码:
#include<stdio.h>
#include<stdbool.h>
int main()
{
int a[1000];
int i;
int n;
int temp=0;
int flag=false;
//int count=0;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
for(i=0;i<n;i++)
{
flag=false;//每一轮交换前都要将flag重新变回false
for(int j=n-1;j>0;j--)
{
if(a[j]<a[j-1])
{
temp=a[j];
a[j]=a[j-1];
a[j-1]=temp;
flag=true;//只要发生了交换就将flag变成true
}
}
if(!flag)//如果没发生交换就退出循环 也就是说明后面的数已经排好了
{
break;
}
for(int h=0;h<n;h++)
{
printf("%d",a[h]);
}
printf("\n");
}
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
运行结果:
选择排序
基本思想:
在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换; 第二次遍历n-2个数,找到最小的数值与第二个元素交换; 。。。 第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。 |
平均时间复杂度: O(n2)
代码如下:
#include<stdio.h>
#include<string.h>
int main()
{
int a[100];//输入的无序数组
int n;//数组个数
scanf("%d", &n);//输入数组个数
int i;//循环变量
int j;//循环变量
int minIndex;//记录值最小的下标
memset(a, 0, n * sizeof(int));//数组初始化为0
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);//数组赋值
}
for (i = 0; i < n - 1; i++)//这里i<n-1是表示外层循环只需要到数组中的倒数第二个数就可以了 (因为只剩下一个数肯定就是最大值就不用继续比较了)
{
minIndex = i;//先记录出挑选出最小值后要交换的位置
for (j = i + 1; j < n; j++)//这里j=i+1表示前面的数已经拍好序了 肯定比后面的数要小 就不用就行比较了 而这里j<n表示从i+1位到最后一位都是需要比较出最小值的
{
if (a[j] < a[minIndex])
{
minIndex = j;//如果有更小的值 则记录下标
}
}
if (minIndex != i)//如果发生了交换就进行数组值交换(记录的下标的数组的值与记录的交换的位置的下标的值)
{
int temp = a[minIndex];
a[minIndex] = a[i];
a[i] = temp;
}
//以下注释掉的是测试代码
//for (int h = 0; h < n; h++)
//{
// printf("%d ", a[h]);
//}
//printf("\n");
}
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
}
运行结果:
这里说一下哈 冒泡排序和选择排序其实有一个共同点 就是将其中最大或者最小的数放在数组的第一位或者最后一位依次进行排序 |
(1)冒泡排序是比较相邻位置的两个数,而选择排序是按顺序比较,找最大值或者最小值; |
(2)冒泡排序每一轮比较后,位置不对都需要换位置,选择排序每一轮比较都只需要换一次位置; |
(3)冒泡排序是通过数去找位置,选择排序是给定位置去找数; |
冒泡排序优缺点:
优点:比较简单,空间复杂度较低,是稳定的;
缺点:时间复杂度太高,效率慢;
选择排序优缺点:
优点:一轮比较只需要换一次位置;
缺点:效率慢,不稳定(举个例子5,8,5,2,9 我们知道第一遍选择第一个元素5会和2交换,那么原序列中2个5的相对位置前后顺序就破坏了)。