目前就举例出我所学会的几种算法,并且都是对于内排序而言。
冒泡排序
1. 代码如下:
void bubble_sort_init(int a[SIZE])
{
int i,j;
for(i=0;i<SIZE-1;i++)
{
for(j=i+1;j<SIZE;j++)
{
if(a[i]>a[j])
swap(a[i],a[j]);
}
}
}
大循环控制从下标0开始,往下对比,当对比倒到有比a[0]小的,立马交换两个数的值;照例推,之后寻找出第二小,第三小的。。。。。。
效率太低,而且称不上冒泡,故有了新的改进算法
2. 代码如下:
void bubble_sort_up(int a[SIZE])
{
int i,j;
for(i=0;i<SIZE-1;i++)
{
for(j=SIZE-1;j>i;j--)
{
if(a[j-1]>a[j])
swap(a[j-1],a[j]);
}
}
}
从数组底部开始,一个个小的往上面冒,当然,也可以一个个大的往下面沉。
3:优化后最终的代码
想一想,如果某一次大循环进行了一次比较,然而没有顺序不合理的,于是乎可以不用再进行下面其余的循环,故增设一个flag标志。
void bubble_sort_end(int a[SIZE])
{
int i,j;
int flag=1;//初始为1
for(i=0;i<SIZE-1&&flag;i++)
{
flag=0;
for(j=SIZE-1;j>i;j--)
{
if(a[j-1]>a[j])
swap(a[j-1],a[j]);
flag=1;//本次循环依旧有数据之间的转移
}
}
}
每次进入循环都认作并未进行排序,一旦没有进行过交换,则flag为0,则下次就不需要再进行循环冒泡比较了;
选择排序
void bubble_sort_end(int a[SIZE])
{
int i,j;
int min;//初始为1
for(i=0;i<SIZE-1;i++)
{
min=i;
for(j=i+1;j>SIZE;j++)
{
if(a[min]>a[j])
min=j;
if(min!=i)
swap(a[i],a[min]);
}
}
}
基本思想
每步将一个待排序的对象,按其排序码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止
直接插入排序
#include<stdio.h>
#define SIZE 10
int a[]={1,4,2,3,4,0,7,6,4,9};
void swap(int i,int j)
{
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
void insert_sort(int a[SIZE])
{
int i,j;
for(i=1;i<SIZE;i++)
{
if(a[i]<a[i-1])
{
for(j=i-1;a[j+1]<a[j];j--)
swap(j+1,j);
}
}
}
void main()
{
int i=10;
while(i--)
printf("%d ",a[9-i]);
putchar('\n');
i=10;
insert_sort(a);
while(i--)
printf("%d ",a[9-i]);
}
程序运行结果如下:
1 4 2 3 4 0 7 6 4 90 1 2 3 4 4 4 6 7 9
Process returned 0 (0x0) execution time : 0.302 s
Press any key to continue.
最开始直接让a[0]为已经插好的数据,接着继续处理之和的第二个,也就是a[1];当后面未排序的小于前面已经排好序的则不停地swap往前挪,最终找到合适位置。同理,当新加未排序元素大于之前的元素,则不需排序,因为前面的元素更小,不用比较。
快速排序
#include <stdio.h>
int a[101],n;//定义全局变量,这两个变量需要在子函数中使用
void quicksort(int left,int right)
{
int i,j,t,temp;
if(left>right)
return;
temp=a[left]; //temp中存的就是基准数
i=left;
j=right;
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[left]=a[i];
a[i]=temp;
quicksort(left,i-1);//继续处理左边的,这里是一个递归的过程
quicksort(i+1,right);//继续处理右边的 ,这里是一个递归的过程
}
int main()
{
int i,j,t;
//读入数据
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
quicksort(1,n); //快速排序调用
//输出排序后的结果
for(i=1;i<=n;i++)
printf("%d ",a[i]);
getchar();getchar();
return 0;
}
该算法或许会有些疑问,比如“
为什么要哨兵j先走”
答案:因为如果哨兵i先走,i和j相遇的时候,i和j所在位置的数会是一个大于基准数的数,这时基准数在最左边,这个数再和基准数位置交换,那么基准数左边就有一个大于基准数的数了,这样就达不到目的了(左边全部小于基准数,右边全部大于基准数)
我们解剖一下其原理:
什么时候结束小循环呢?不外乎三种情况
1:正常的结束,j找到一个小于基准数的值,i找到一个大于j的值,之后二者交换,此时排序未接近尾声。
2:当j不停的减一直到找到一个小于基准数的值,此时i继续走,最后由于没有大于基准数的值,所以i=j,跳出所有循环,此时i和j所对应的都为一个小于基准数的元素,所以两者交换,排序完成。
但是另一种情况,j一直未找到小于基准数的值,直到i=j了,此时直接跳出所有循环和判断语句,但是我们知道,上一个循环结束的i对应的元素必是小于i的,所以,j=i其实已经对应着一个小于基准数的值,所以直接交换完成排序。
以上是目前我用过的几种排序。