zoukankan      html  css  js  c++  java
  • 七大经典排序算法

    1、直接插入排序

    基本思想:

       (1)首先对数组的前两个数据进行从小到大排序;

       (2)接着将第3个数据与排好序的两个数进行比较,将第3个数据插入到合适的位置;

       (3)然后将第4个数据插入到上述已排好序的前3个数中;

       (4)不断重复上述过程,知道将最后一个数据插入到合适的位置,最后便完成了对原始数据的从小到大的排序。

    测试程序:

    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    
    #define SIZE 10
    
    void InsertionSort(int a[], int len)    //直接插入排序
    {
        int temp;//临时变量
        int i,j,k;
    
        for(i=1;i<len;i++)
        {
            temp=a[i];
            j=i-1;
            while((j>=0) && (temp<a[j]))  //这里while不能换成if,if只是一次判定,while具有循环判定的功能
            {
                a[j+1]=a[j];
                j--;
            }
            a[j+1]=temp;
    
            printf("第%d步直接插入排序的结果为:",i);
            for(k=0;k<len;k++)
            {
                printf("%d ",a[k]);
            }
            printf("
    ");
        }
    }
    
    void main()
    {
        int arr[SIZE];
        int i;
    
        srand(time(NULL)); 
        //time(NULL)返回当前时间,意思是以当前系统时间作为随机数的种子来产生随机数!
        //至于NULL这个参数,只有设置成NULL才能获得系统的时间; 
        //srand 是对随机数生成器进行初始化操作,设置随数种子
    
        for(i=0;i<SIZE;i++)
        {
            arr[i]=rand()%(1000-100)+100; //产生100到1000之内的随机数
        }
    
        printf("排序前的序列如下:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",arr[i]);
        }
    
        printf("
    ");
    
        InsertionSort(arr,SIZE);
    
        printf("直接插入排序后的序列如下:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",arr[i]);
        }
    
        printf("
    ");
    
        system("pause");
        
    }

    测试结果:

    2、希尔排序(缩小增量排序)

    基本思想:

         (1)先选取一个小于n的整数(称之为步长)di,然后将n个待排序的数据序列划分成di个子序列;

         (2)从第1个数据开始,间隔为di的数据为同一个序列,然后分别对每一个子序列进行直接插入排序;

         (3)一趟之后,间隔为di的数据有序,随着有序性的改善,继续减小步长di,如此反复进行,知道步长di=1;

         (4)此时再对所有记录进行一次直接插入排序即可。

    测试程序:

    这里步长取n/2,n/4....

    /* 希尔排序(缩短增量排序) */
    
    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    
    #define SIZE 10
    
    
    
    void ShellSort(int a[],int len) //希尔排序(参数:数组,数组长度)
    {
        int i,j,k;
        int temp,r;
        int x=0;
    
        for(r=len/2;r>=1;r/=2)
        {
            for(i=r;i<len;i++)
            {
                temp=a[i];
                j=i-r;
                while(j>=0 && temp<a[j])
                {
                    a[j+r]=a[j];
                    j-=r;
                }
                a[j+r]=temp;
            }
    
            x++;
            printf("第%d步希尔排序结果为:",x);
            for(k=0;k<len;k++)
            {
                printf("%d ",a[k]);
            }
            printf("
    ");
        }
    }
    
    void main()
    {
        int i;
        int arr[SIZE];
    
        srand(time(NULL));
        for(i=0;i<SIZE;i++)
        {
            arr[i]=rand()%(1000-100)+100;
        }
        printf("排序前的数据序列如下:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",arr[i]);
        }
        printf("
    ");
    
        ShellSort(arr,SIZE);
        
        printf("希尔排序后的数据序列如下:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",arr[i]);
        }
        printf("
    ");
    
        system("pause");
    
    }

    测试结果:

    3、冒泡排序

    基本思想:

        (1)对数据序列中各数据,依次比较相邻的两个数据元素的大小;

        (2)如果前面的数据大于后面的数据,就交换这两个数据,经过一轮的多次比较排序,就可将最小的数据排到首位;

        (3)然后,再用同样的方法把剩下的数据逐个进行比较。

    测试程序:

    本测试程序从尾部开始进行两两比较

    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    
    #define SIZE 10
    
    void BubbleSort(int a[],int len)
    {
        int i,j,k;
        int temp;
    
        for(i=0;i<len-1;i++)
        {
            for(j=len-1;j>i;j--)
            {
                if(a[j-1]>a[j])
                {
                    temp=a[j-1];
                    a[j-1]=a[j];
                    a[j]=temp;
                }
            }
    
            printf("第%d步冒泡排序结果为:",i);
            for(k=0;k<len;k++)
            {
                printf("%d ",a[k]);
            }
            printf("
    ");
        }
    }
    
    void main()
    {
        int i;
        int arr[SIZE];
    
        srand(time(NULL)); //随机种子
    
        for(i=0;i<SIZE;i++)
        {
            arr[i]=rand()%(1000-100)+100;   //产生排序前的随机序列(100到1000内的三位数)
        }
    
        printf("排序前的数据序列如下:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",arr[i]);
        }
    
        printf("
    ");
    
        BubbleSort(arr,SIZE);
    
        printf("冒泡排序后的数据序列如下:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",arr[i]);
        }
    
        printf("
    ");
    
        system("pause");
    }

    测试结果:

    4、快速排序

    基本思想:

    注:快速排序与冒泡排序类似,都是基于交换排序思想,是冒泡排序的改进 

    1. 首先设定一个分界值,提高该分界值将数组分成左右两部分
    2. 将大于等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于等于分界值,而右边部分中各元素都大于等于分界值
    3. 然后,左边和右边的数据可以再独立排序。对于左侧的数据,又可以去一个分界值,将该部分的数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以类似处理
    4. 重复上述过程,可以看出,这是一个递归过程。

    测试程序:

    /* 快速排序  */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define SIZE 18
    
    void QuickSort(int *arr, int left, int right)
    {
        int f,t;
        int rtemp,ltemp;
    
        ltemp=left;
        rtemp=right;
        f=arr[(left+right)/2];   //将中间值作为分界值
        while(ltemp<rtemp)
        {
            while(arr[ltemp]<f)
            {
                ++ltemp;
            }
            while(arr[rtemp]>f)
            {
                --rtemp;
            }
            if(ltemp<=rtemp)
            {
                t=arr[ltemp];
                arr[ltemp]=arr[rtemp];
                arr[rtemp]=t;
                --rtemp;
                ++ltemp;
            }
        }
        if(ltemp==rtemp)
        {
            ltemp++;
        }
        if(left<rtemp)
        {
            QuickSort(arr,left,ltemp-1);   //递归调用
        }
        if(ltemp<right)
        {
            QuickSort(arr,rtemp+1,right);  //递归调用
        }
    }
    
    
    void main()
    {
        int i;
        int shuzu[SIZE];
    
        srand(time(NULL));  //初始化数组
        for(i=0;i<SIZE;i++)
        {
            shuzu[i]=rand()/1000+100;  //随机产生个三位数的随机数,存在数组arr中
        }
    
    
        printf("排序前:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",shuzu[i]);
        }
        printf("
    ");
    
        QuickSort(shuzu,0,SIZE-1);    //调用函数QuickSort,对数组进行排序
    
        printf("排序后:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",shuzu[i]);
        }
        printf("
    ");
        
        system("pause");
    }

    测试结果:

    5、选择排序

    基本思想:

    1. 首先从原始数据中选择最小的一个数据,将其和位于第一个位置的数据交换
    2. 接着从剩下的n-1个数据中选择次小的一个元素,将其和位于第二个位置的数据交换
    3. 然后,这样不断重复,知道最后两个数据交换完成。

     测试程序:

    /* 选择排序   */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define SIZE 10
    
    void SelectionSort(int *a,int len)
    {
        int i,j,k,h;
        int temp;
    
    
        for(i=0;i<len-1;i++)
        {
            k=i;
            for(j=i+1;j<len;j++)
            {
                if(a[j]<a[k])
                    k=j;
            }
            if(k!=i)
            {
                temp=a[i];
                a[i]=a[k];
                a[k]=temp;
            }
    
            printf("第%d步排序结果:",i);
    
            for(h=0;h<len;h++)
            {
                printf("%d ",a[h]);
            }
    
            printf("
    ");
        }
    }
    
    
    void main()
    {
        int i;
        int shuzu[SIZE];
    
        srand(time(NULL));  //初始化数组
        for(i=0;i<SIZE;i++)
        {
            shuzu[i]=rand()/1000+100;  //随机产生个三位数的随机数,存在数组arr中
        }
    
    
        printf("排序前:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",shuzu[i]);
        }
        printf("
    ");
    
    
        SelectionSort(shuzu,SIZE);
    
        printf("排序后:
    ");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",shuzu[i]);
        }
        printf("
    ");
    
        system("pause");
    }

    测试结果:

     6、堆排序

    基本概念:

    堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。

    堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
    (1)用大根堆排序的基本思想
    ① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
    ② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
    ③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
    ……
    直到无序区只有一个元素为止。
    (2)大根堆排序算法的基本操作:
    ① 初始化操作:将R[1..n]构造为初始堆;
    ② 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。

    注意

    ①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。
    ②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。堆排序和直接选择排序相反:在任何时刻堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止

    测试程序:

    // array是待调整的堆数组,i是待调整的数组元素的位置,nlength是数组的长度
    //本函数功能是:根据数组array构建大根堆
     
    void HeapAdjust(int array[], int i, int nLength)
    {
        int nChild;
        int nTemp;
        for (nTemp = array[i]; 2 * i + 1 < nLength; i = nChild)
        {
            // 子结点的位置=2*(父结点位置)+ 1
            nChild = 2 * i + 1;
            // 得到子结点中较大的结点
            if (nChild < nLength - 1 && array[nChild + 1] > array[nChild])
                ++nChild;
            // 如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点
            if (nTemp < array[nChild])
                array[i] = array[nChild];
            else
            // 否则退出循环
                break;
            // 最后把需要调整的元素值放到合适的位置
            array[nChild]= nTemp;
        }
    }
     
    // 堆排序算法
    void HeapSort(int array[],int length)
    {
        // 调整序列的前半部分元素,调整完之后第一个元素是序列的最大的元素
        //length/2-1是第一个非叶节点,此处"/"为整除
        for (int i = length / 2 - 1; i >= 0; --i)
            HeapAdjust(array, i, length);
        // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素
        for (int i = length - 1; i > 0; --i)
        {
            // 把第一个元素和当前的最后一个元素交换,
            // 保证当前的最后一个位置的元素都是在现在的这个序列之中最大的
            Swap(&array[0], &array[i]);
            // 不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值
            HeapAdjust(array, 0, i-1);
        }
    }

     7、归并排序

    基本思想:

         (1)将n个数据序列看成有n个长度为1的有序子序列;

         (2)将上述子序列两两合并,得到长度为2的若干有序子表;

         (3)然后,再对上述子表两两合并,得到长度为4的若干子表;

                   ........

         (4)重复上述过程,直到最后的子表长度为n。从而完成排序过程。

    测试程序:

    #include<stdio.h>
    #include<stdlib.h>
    #include<time.h>
    
    #define SIZE 15
    
    
    void MergeOne(int a[],int b[],int n,int len)
    /* 完成一遍合并
    参数a为一个数组,用来存放待排序数据,n表示数组a中数据总数
    参数b为一个数组,用来存放排序后的数据,len表示每个有序子表的长度*/
    {
        int i,j,k;
        int s,e;
    
        s=0;
    
        while(s+len<n)
        {
            e=s+2*len-1;
            if(e>=n)    //最后一段可能少于len个节点
            {
                e=n-1;
            }
            //相邻有序子表合并
            k=s;
            i=s;
            j=s+len;
    
            while((i<s+len) && (j<=e))  //如果两个有序表都未结束时,循环比较
            {
                if(a[i]<=a[j])    //将较小的数据复制到数组b中
                {
                    b[k++]=a[i++];
                }
                else
                {
                    b[k++]=a[j++];
                }
            }
            while(i<s+len)    
            {
               b[k++]=a[i++];    //未合并的部分复制到数组b中
            }
            while(j<=e)
            {
                b[k++]=a[j++];   //未合并的部分复制到数组b中
            }
    
            s=e+1;   //下一段有序段左段的开始下标
        }
    
        if(s<n)    //将剩余的一个有序段从数组a中复制到数组b中
        {
            for(;s<n;s++)
            {
                b[s]=a[s];
            }
        }
    }
    
    
    void MergeSort(int a[],int n)  /* 归并排序  */
    {
        int *p;
        int h,count,len,f;
    
        count=0;  //排序步骤计数器
        len=1;  //有序序列的长度
        f=0;  //标志
        if(!(p=(int *)malloc(sizeof(int)*n)))
        {
            printf("内存分配失败!
    ");
            exit(0);
        }
    
        while(len<n)
        {
            if(f==1) //交替在a和p之间合并
            {
                MergeOne(p,a,n,len);  //p合并到a
            }
            else
            {
                MergeOne(a,p,n,len);  //a合并到p
            }
            len=len*2; //增加有序序列长度为原来的2倍
            f=1-f;  //使f的值在0和1之间切换
    
            count++;
            printf("第%d步为:",count);
            for(h=0;h<SIZE;h++)
            {
                printf("%d ",a[h]);
            }
            printf("
    ");
        }
        if(f) //如果进行了排序
        {
            for(h=0;h<n;h++)
            {
                a[h]=p[h];  //将内存p中的数据复制到数组a中
            }
    
            free(p); //释放内存
        }
    }
    
    void main()
    {
        int i;
        int shuzu[SIZE];
    
        srand(time(NULL));
        for(i=0;i<SIZE;i++)
        {
            shuzu[i]=rand()%(1000-100)+100;
        }
        printf("排序前为:");
        for(i=0;i<SIZE;i++)
        {
            printf("%d ",shuzu[i]);
        }
        printf("
    ");
    
        MergeSort(shuzu,SIZE);
    
        printf("排序后为:");
        for(i=0;i<=SIZE;i++)
        {
            printf("%d ",shuzu[i]);
        }
        printf("
    ");
    
        system("pause");
    }

    测试结果:

    8、小结

    排序效率的一个重要指标——速度

    计算复杂度,一般依据数据量的大小n来度量,主要表征了算法的执行速度(算法优劣的一个重要指标)

    (1)选择排序法:平均速度O(n2),最坏情况下的速度为O(n2);

    (2)快速排序法:平均速度O(nlogn),最坏情况下的速度为O(n2);

    (3)冒泡排序法:平均速度O(n2),最坏情况下的速度为O(n2);

    (4)直接插入排序法:平均速度O(n2),最坏情况下的速度为O(n2);

    (5)堆排序法:平均速度O(nlogn),最坏情况下的速度为O(nlogn):

    (6)希尔排序法:平均速度O(n3/2),最坏情况下的速度为O(n2);

    (7)归并排序法:平均速度O(nlogn),最坏情况下的速度为O(nlogn):

  • 相关阅读:
    Firefox浏览器怎么安装adobe flash player插件
    uploadify在火狐下上传不了的解决方案,java版(Spring+SpringMVC+MyBatis)详细解决方案...
    thinkphp模版调用函数方法
    Thinkphp模板中函数的使用
    60.0.1(64位)windows版 uploadify使用有问题
    一起谈.NET技术,异步调用与多线程的区别 狼人:
    一起谈.NET技术,Silverlight中使用递归构造关系图 狼人:
    一起谈.NET技术,ASP.NET Routing对请求的处理方式 狼人:
    一起谈.NET技术,闲话“多线程” 狼人:
    一起谈.NET技术,利用.NET Framework4.0的源代码调试你的应用程序 狼人:
  • 原文地址:https://www.cnblogs.com/kkdd-2013/p/3304878.html
Copyright © 2011-2022 走看看