排序算法

来源:互联网 发布:ae软件下载官方中文版 编辑:程序博客网 时间:2024/06/08 11:35

排序

4.1 插入排序

先找到位置,再把该位置后的数都后移一位,最后才在该位置插入。

4.1.1简单插入排序

将一个记录插入到已排好序的有序表中,从而得到一个新的、记录数增1的有序表。

实现方法:把第n个元素与第n-1个元素进行比较,在这次比较中,如果第n个元素要小,则把第n-1个元素向后移一位。这样直到比第n个元素小时才结束。

 

void insertsort(int a[],int n)

{

    int i,j;

    int tmp;

    for(i=1;i<n;i++)

    {

       tmp=a[i];

       j=i-1;

       while(tmp<a[j])

       {

           a[j+1]=a[j];

           j--;

       }

       a[j+1]=tmp;

    }

}

 

4.1.2 二路插入排序

用二分查找的方法找到要插入的位置,然后把该位置后的元素都后移一位,把添加的元素插入到该位置。要主要后移时结束条件为:i>=low.

void BInsertsort(int a[],int n)

{

    int low,high,k,tmp,m;   //low,high表示当前循环中最前一个位置和最后一个位置,k表示插入第几个元素

    for(k=1;k<n;k++)

    {

       low=0;

       high=k-1;

       tmp=a[k];

       while(low<=high)

       {

           m=(low+high)/2;

           if(tmp>a[m])

                low=m+1;

           else

                high=m-1;

       }

       for(inti=k-1;i>=low;i--)

           a[i+1]=a[i];

       a[low]=tmp;

    }

}

4.1.3希尔排序

先把整个待排元素序列分割为若干个子序列(距离为“增量”),在子序列上进行直接插入排序,然后再缩减增量,待整个序列中的元素基本有序时,再对全体元素进行一次插入排序。

void shellsort(int a[],int n)

{

    int i,j;

    int tmp;

    int gap=n/2;

    while(gap>0)

    {

       for(i=gap;i<n;i++)

       {

           tmp=a[i];

           j=i-gap;

           while(j>=0&&tmp<a[j])

           {

                a[j+gap]=a[j];

                j-=gap;

           }

           a[j+gap]=tmp;

       }

       gap/=2;

    }

}

 

4.2 交换排序

相邻元素交换顺序。

4.2.1冒泡排序

N个元素进行排序,两两比较待排序的元素,发现两个元素的次序相反时即进行交换,重复n-1次。

void bubblesort(int a[],int n)

{

    int i,j,tmp;

    for(i=0;i<n-1;i++)

       for(j=n-1;j>i;j--)

       {

           if(a[j-1]>a[j])

           {

                tmp=a[j];

               a[j]=a[j-1];

                a[j-1]=tmp;

           }

       }

}

4.2.2快速排序——void quicksort(int a[],int low,int high)

通过一趟排序将待排元素分割成独立的两部分,其中一部分的元素都比另一部分小,则分别对这两部分进行排序,最后达到整体有序。

使用了递归的方法

void quicksort(int a[],int low,int high)

{

    int i,j,tmp;

    i=low;

    j=high;

    if(low<high)

    {

       tmp=a[low];

       while(low<high)

       {

           while(low<high&&a[high]>=tmp)

                high--;

           a[low]=a[high];

           while(low<high&&a[low]<=tmp)

                low++;

           a[high]=a[low];

       }

       a[low]=tmp;

       quicksort(a,i,low-1);

       quicksort(a,low+1,j);

    }

}

4.3 选择排序

从数组中选出最小(最大)的元素依次排列。

4.3.1简单选择排序

思想:每趟从待排序元素中选出最小的一个元素,顺序放在已排好序的末尾。

实现方法:假设位置i后再没有比位置i上的元素大的元素,遍历i+1到n-1,查找是否有比a[i]小的元素,若有就交换位置。

void selectsort(int a[],int n)

{

    int i,j,k,tmp;

    for(i=0;i<n;i++)

    {

       k=i;

       for(j=i+1;j<n;j++)

       {

           if(a[j]<a[k])

                k=j;

       }

       if(k!=i)

       {

           tmp=a[k];

           a[k]=a[i];

           a[i]=tmp;

       }

    }

}

4.3.2堆排序——两个函数voidheapadjust(int d[],int ind, int len);Voidheapsort(inta[],int n)

对heapsort函数,先对原数组建立大顶堆,再遍历数组依次交换a[0]与a[n-j-1],最后对a[0]~a[n-j-1]建立大顶堆。建立大顶堆的目的是把数组中最大的元素放到a[0]位置上。

对heapadjust函数,先找到顶点i和其左孩子节点2*i+1,左孩子未遍历到数组末尾时判断是否存在右孩子节点,如果存在且右孩子节点大于左孩子节点,则左孩子下标加1(得到要被交换的节点),判断要被交换的节点是否比父节点i大,大则交换两者值,再设置父节点和左孩子节点。

//#筛选算法#%

void heapadjust(int d[],int ind,int len)

{

    //#i为要筛选的节点#%

    int i = ind;

 

    //#c中保存i节点的左孩子#%

    int c = i * 2+ 1; //#+1的目的就是为了解决节点从0开始而他的左孩子一直为0的问题#%

 

    while(c< len)//#未筛选到叶子节点#%

    {

       //#如果要筛选的节点既有左孩子又有右孩子并且左孩子值小于右孩子#%

       //#从二者中选出较大的并记录#%

       if(c+ 1 < len && d[c] <d[c+ 1])

           c++;

       //#如果要筛选的节点中的值大于左右孩子的较大者则退出#%

       if(d[i]> d[c])break;

        else

       {

           //#交换#%

           int t = d[c];

           d[c]= d[i];

           d[i]= t;

           //

           //#重置要筛选的节点和要筛选的左孩子#%

           i = c;

           c = 2 * i +1;

       }

    }

    return;

}

 

void heapsort(int d[],int n)

{

    //#初始化建堆, i从最后一个非叶子节点开始#%

    for(inti = (n - 2) / 2; i>= 0; i--)

       heapadjust(d, i, n);

 

    for(int j= 0; j< n; j++)

    {

                //#交换#%

       int t = d[0];

       d[0]= d[n- j -1];

       d[n - j -1] = t;

 

       //#筛选编号为0 #%

       heapadjust(d,0, n- j -1);

    }

}

4.4 归并排序voidMerge(int r[],int r1[],int s,int m,int t); void MergeSort(int r[],int r1[],int s,int t)

 

采用分治算法,即将一组元素通过几次平分,分成若干组元素(最终单个元素为一组),这样就形成了一个满二叉树形结构,叶子节点为单个元素,归属于同一个父节点的两组元素排序后归并成一组元素,最终归属于根节点的两组元素再次归并成一组元素。

void Merge(int r[],int r1[],int s,int m,int t)

{

    int i=s;

    int j=m+1;

    int k=s;

    while(i<=m&&j<=t)

    {

       if(r[i]<=r[j])

           r1[k++]=r[i++];

       else

           r1[k++]=r[j++];

    }

    if(i<=m)

       while(i<=m)

           r1[k++]=r[i++];

    else

       while(j<=t)

           r1[k++]=r[j++];

 

    for(int n=s;n<=t;n++)

       r[n]=r1[n];

}

 

void MergeSort(int r[],int r1[],int s,int t)

{

    if(s<t)

    {

       int m=(s+t)/2;  //a[8],函数调用MergeSort(a,b,0,7)

       MergeSort(r,r1,s,m);

       MergeSort(r,r1,m+1,t);

       Merge(r,r1,s,m,t);

    }

}

4.5 基数排序intmaxbit(int data[],int n); void radixsort(intdata[],int n)

思想:   是一种借助多关键字排序的思想对单逻辑关键字进行排序的方法,又称为“桶子法”,即通过键值,将要排序的元素分配到某些“桶”中。

实现方法:

 

最低位优先(LSD)方法——即从低位向高位排序

 

将整形10进制按每位拆分,然后从低位到高位依次比较各个位。主要分为两个过程:

(1)分配,先从个位开始,根据位值(0-9)分别放到0~9号桶中(比如53,个位为3,则放入3号桶中)

(2)收集,再将放置在0~9号桶中的数据按顺序放到数组中

重复(1)(2)过程,从个位到最高位(比如32位无符号整形最大数4294967296,最高位10位)

//这里求数组中元素的最大位数的方法很好

int maxbit(int data[],int n)//辅助函数,求数据的最大位数

{

    int d =1;//保存最大的位数

    int p =10;

    for(int i= 0;i< n;++i)

    {

       while(data[i]>= p)

       {

           p *= 10;

           ++d;

       }

    }

    return d;

}

 

void radixsort(int data[],int n)//基数排序

{

    int d = maxbit(data,n);

    int * tmp= new int[n];

    int * count= new int[10];//计数器

    int i,j,k;

    int radix =1;

    for(i= 1; i<= d;i++)//进行d次排序

    {

       for(j= 0;j< 10;j++)

           count[j]= 0;//每次分配前清空计数器

 

       for(j= 0;j< n; j++)

       {

           k = (data[j]/radix)%10;//统计每个桶中的记录数

           count[k]++;

       }

 

       for(j= 1;j< 10;j++)

           count[j]= count[j-1]+ count[j];//tmp中的位置依次分配给每个桶,因为相同的某一位可能有几个数,所以要用递增的形式计算下标

 

        for(j =n-1;j>= 0;j--) //将所有桶中记录依次收集到tmp

        {

           k = (data[j]/radix)%10;

           tmp[count[k]-1] = data[j];

           count[k]--;

        }

       for(j= 0;j< n;j++)//将临时数组的内容复制到data

           data[j]= tmp[j];

       radix = radix*10;

    }

    delete [] tmp;

   delete [] count;

}

4.6 排序算法比较


数据原始状态对排序的影响:

1)       当原表有序或基本有序时,插入排序(简单插入排序、二路插入排序、希尔排序)和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);

2)       而快速排序则相反,当原表基本有序时,将蜕化为冒泡排序,时间复杂度提高为O(n2);

3)       原表是否有序,对选择排序(简单选择排序、堆排序)、归并排序和基数排序的时间复杂度影响不大。

4)       所有选择排序都是不稳定的且不受原表顺序的影响。

其它总结:

 

1)       从平均时间性能而言,快速排序最佳,所需时间最省,但在最坏的情况下,时间性能不如堆排序和归并排序,后两者相比较的结果是,在n比较大时,归并排序所需时间较堆排序省,但所需辅助存储量最多。

2)       简单排序包括:除希尔排序外的所有插入排序冒泡排序简单选择排序

3)       基数排序的时间复杂度也可以写成O(d*n)。因此,它最适合n值很大而关键字较小的序列。

4)       基数排序是稳定的内排方法,所有时间复杂度为O(n2)的简单排序法都是稳定的。快速排序、堆排序和希尔排序等时间性能较好的排序方法都是不稳定的。一般来说,排序过程中的“比较”是在“相邻的两个记录关键字”间进行的排序方法是稳定的。稳定性由方法本身决定。

稳定:除希尔排序外的所有插入排序、冒泡排序、归并排序和基数排序;

不稳定:希尔排序,所有选择排序(简单选择排序和堆排序)、快速排序。

影响:插入排序和交换排序

不影响:选择排序,归并排序和基数排序


引用的文章

http://www.cnblogs.com/mengdd/archive/2012/11/30/2796845.html


0 0
原创粉丝点击