经典排序算法

 

     1.冒泡排序法

   它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

  这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端,故名。

  由于冒泡排序简洁的特点,它通常被用来对于计算机程序设计入门的学生介绍算法的概念。

冒泡C语言代码

复制代码
#include<stdio.h>
#define SIZE 8
void bubble_sort(int a[],int n)//n为数组a的元素个数
{
int i,j,temp;
for(j=0;j<n-1;j++)
for(i=0;i<n-1-j;i++)
{
if(a[i]>a[i+1])//数组元素大小按升序排列
{
temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
}
}
}
int main()
{
int number[SIZE]={95,45,15,78,84,51,24,12};
int i;
bubble_sort(number,SIZE);
for(i=0;i<SIZE;i++)
{
printf("%d",number[i]);
}
printf("\n");
}
复制代码

    2.直接插入排序法

  插入排序法就是检查第i个数字,如果在它的左边的数字比它大,进行交换,这个动作一直继续下去,直到这个数字的左边数字比它还要小,就可以停止了。插入排序法主要的回圈有两个变数:i和j,每一次执行这个回圈,就会将第i个数字放到左边恰当的位置去。

  每次从无序表中取出第一个元素,把它插入到有序表的合适位置,使有序表仍然有序

  第 趟比较前两个数,然后把第 二个数按大小插入到有序表中; 第二趟把 第三个数据与 前两个数从前向后扫描,把第三个数按大小插入到有序表中;依次进行下去,进行了 (n-1)趟扫描以后就完成了整个排序过程。
  直接插入排序属于稳定的排序,最坏 时间复杂性为O(n^2), 空间复杂度为O(1)。
  直接插入排序是由 两层嵌套循环组成的。外层循环标识并决定待比较的数值。内层循环为待比较数值确定其最终位置。直接插入排序是将待比较的数值与它的前一个数值进行比较,所以外层循环是从第二个数值开始的。当前一数值比待比较数值大的情况下继续循环比较,直到找到比待比较数值小的并将待比较数值置入其后一位置,结束该次循环。
  值得注意的是,我们必需用一个 存储空间来保存当前待比较的数值,因为当一趟比较完成时,我们要将待比较数值置入比它小的数值的后一位 插入排序类似玩牌时整理手中纸牌的过程。插入排序的基本方法是:每步将一个待排序的记录按其关键字的大小插到前面已经排序的序列中的适当位置,直到全部记录插入完毕为止。
复制代码
#include<stdio.h>

int main()
{
    int a[]={98,76,109,34,67,190,80,12,14,89,1};
    int k=sizeof(a)/sizeof(a[0]);//使用 sizeof把a所有的内存大小读出
    int i,j;                    //sizeof(a[0])把a中一个元素的大小,
                                //在用总的除以一个的得到长度。
    for(i=2;i<k;i++)//循环从第3个元素开始
    {
        if(a[i]<a[i-1])    //后面一个小于前面一个
        {
            int temp=a[i];        //将a[i]的值赋给temp
            for(j=i-1;j>=0&&a[j]>temp;j--)    //嵌套循环 从i-1,直到a[j]大于temp
                a[j+1]=a[j];            //把a[i]与a[i-1]交换
            a[j+1]=temp;                //循环完将temp移动到有序处                
        }
    }
    for(i=0;i<k;i++)
    {
        printf("%d ",a[i]);
    }
    return 0;
}
 
复制代码

  3.直接选择排序算法

  直接选择排序(Straight Select Sorting) 也是一种简单的排序方法,它的基本思想是:第一次从R[0]~R[n-1]中选取最小值,与R[0]交换,第二次从R[1]~R[n-1]中选取最小值,与R[1]交换,....,第i次从R[i-1]~R[n-1]中选取最小值,与R[i-1]交换,.....,第n-1次从R[n-2]~R[n-1]中选取最小值,与R[n-2]交换,总共通过n-1次,得到一个按排序码从小到大排列的有序序列·

  例如:给定 n=8数组R中的8个元素的排序码为(8,3,2,1,7,4,6,5),则直接选择排序的过程如下所示
由于百科不方便画出关联箭头 所以用 n -- n 表示 :
初始状态 [ 8 3 2 1 7 4 6 5 ] 8 -- 1
第一次 [ 1 3 2 8 7 4 6 5 ] 3 -- 2
第二次 [ 1 2 3 8 7 4 6 5 ] 3 -- 3
第三次 [ 1 2 3 8 7 4 6 5 ] 8 -- 4
第四次 [ 1 2 3 4 7 8 6 5 ] 7 -- 5
第五次 [ 1 2 3 4 5 8 6 7 ] 8 -- 6
第六次 [ 1 2 3 4 5 6 8 7 ] 8 -- 7
第七次 [ 1 2 3 4 5 6 7 8 ] 排序完成
复制代码
#include<stdio.h>
void SelectSort(int R[], int n)//类型int可以改为其他类型。n为数组长度
{
    int i,j,m;
    int t;
    for(i=0;i<n-1;i++)    //循环n-1次
    {
        m = i;
        for(j=i+1; j<n; j++)//嵌套循环 每次循环把i后面的最小数返回给i
        {
            if(R[j]<R[m])
            m=j;
        }
        if(m!=i)        //m改变则改变数组的值
        {
            t=R[i];
            R[i]=R[m];
            R[m]=t;
        }
    }
}
/*        以下为演示算法
main()
{
    int a[8]={8,3,2,1,7,4,6,5},i;
    SelectSort(a,8);
    for(i=0;i<8;i++)
        printf("%d ",a[i]);
}
*/
复制代码

   4.快速排序算法

  快速排序(Quicksort)是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归行,以此达到整个数据变成有序序列。

 
  设要排序的 数组是A[0]……A[N-1],首先任意选取一个数据( 通常选用数组的第一个数)作为关键数据,然后将所有比 它小的数都放到它前面,所有比 它大的数都放到它后面,这个过程称为 一趟快速排序。值得注意的是,快速排序 不是一种稳定的排序算法,也就是说,多个 相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:
1)设置两个 变量i、j, 排序开始的时候:i=0,j=N-1;
2)以第一个 数组元素作为关键数据,赋值给 key,即 key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于 key的值A[j],将A[j]赋给A[i];
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于 key的A[i],将A[i]赋给A[j];
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即 3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候 i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)
复制代码
#include<stdio.h>
void QuickSort(int a[],int numsize)//a是整形数组,numsize是元素个数
{
    int i=0,j=numsize-1,t;
    int val=a[0];//指定参考值val大小
    if(numsize>1)//确保数组长度至少为2,否则无需排序
    {
        while(i<j)//循环结束条件(i==j)
        {
            for(;j>i;j--)//从后向前搜索比val小的元素,找到后填到a[i]中并跳出循环
            {printf("垃圾1 ");
            if(a[j]<val)
            {    printf("垃圾3 ");
                a[i]=a[j];
                for(t=0;t<numsize;t++)
                    printf("%d ",a[t]);
                printf("\n");
                break;
            }}
            for(;i<j;i++)//从前往后搜索比val大的元素,找到后填到a[j]中并跳出循环
            {printf("垃圾2 ");
            if(a[i]>val)
                {printf("垃圾4 ");
                    a[j]=a[i];
                    for(t=0;t<numsize;t++)
                    printf("%d ",a[t]);
                printf("\n");
                    break;
            }    }
        }
        a[i]=val;//将保存在val中的数放到a[i]中
        QuickSort(a,i);//递归,对前i个数排序
        QuickSort(a+i+1,numsize-1-i);//对i+1到numsize这numsize-1-i个数排序
    }
}

main()
{
    int a[8]={8,5,7,6,2,4,1,3},n=8,i;
    QuickSort(a,n);
    for(i=0;i<n;i++)
        printf("%d ",a[i]);

}

复制代码

  5.归并排序算法

  归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为干个有序的子序列,再把有序的子序列合并为整体有序序列

  归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。值得注意的是归并排序是一种稳定的排序方法。

  将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序 ,称为二路 归并
  例如有两个有序表:(7,10,13,15)和(4,8,19,20),归并后得到的有序表为:(4,7,8,10,13,15,19,20)。
  归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1,如此循环下去,知道其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元。
二路归并算法描述为(a[s,t]中的数据由小到大合并到r[s,t]中);
procedure merge(s,m,t);
begin
1) i:=s; j:=m+1; k:=s;
2) while (i<=m) and (j<=t) do
if a[i]<=a[j] then (r[k]:=a[i]; i:=i+1; k:=k+1)
else (r[k]:=a[j]; j:=j+1; k:=k+1);
3) while i<=m do (r[k]:=a[i]; i:=i+1; k:=k+1);
4) while j<=t do (r[k]:=a[j]; j:=j+1; k;=k+1);
end;
  归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

  归并操作(merge),也叫归并算法,指的是将两个顺序序列合并成一个顺序序列的方法。

如 设有数列{6,202,100,301,38,8,1}
初始状态:6,202,100,301,38,8,1
第一次归并后:{6,202},{100,301},{8,38},{1},比较次数:3;
第二次归并后:{6,100,202,301},{1,8,38},比较次数:4;
第三次归并后:{1,6,8,38,100,202,301},比较次数:4;
总的比较次数为:3+4+4=11,;
逆序数为14;
复制代码
#include<stdio.h>
void Merge(int sourceArr[],int targetArr[],int startIndex,int midIndex,int endIndex)
{
    int i,j,k;
    for(i=midIndex+1,j=startIndex;startIndex<=midIndex&&i<=endIndex;j++)
    {
        if(sourceArr[startIndex]<sourceArr[i])
        {
            targetArr[j]=sourceArr[startIndex++];
        }
        else
        {
            targetArr[j]=sourceArr[i++];
        }
    }
 
    if(startIndex<=midIndex)
    {
        for(k=0;k<=midIndex-startIndex;k++)
        {
            targetArr[j+k]=sourceArr[startIndex+k];
        }
    }
 
    if(i<=endIndex)
    {
        for(k=0;k<=endIndex-i;k++)
        {
            targetArr[j+k]=sourceArr[i+k];
        }
    }
}
//内部使用递归,空间复杂度为n+logn
void MergeSort(int sourceArr[],int targetArr[],int startIndex,int endIndex)
{
    int midIndex;
    int tempArr[100];//此处大小依需求更改
    if(startIndex==endIndex)
    {
        targetArr[startIndex]=sourceArr[startIndex];
    }
    else
    {
        midIndex=(startIndex+endIndex)/2;
        MergeSort(sourceArr,tempArr,startIndex,midIndex);
        MergeSort(sourceArr,tempArr,midIndex+1,endIndex);
        Merge(tempArr,targetArr,startIndex,midIndex,endIndex);
    }
}
 
//调用
int main(int argc,char *argv[])
{
    int a[8]={50,10,20,30,70,40,80,60};
    int b[8],i;
    MergeSort(a,b,0,7);
    for(i=0;i<sizeof(a)/sizeof(*a);i++)
        printf("%d ",b[i]);
    printf("\n");
    system("pause");
    return 0;
}
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值