排序算法(直接插入,堆排,归并排序)

      1. 直接插入排序

         思想:其基本思路就是将一个数插入一个已经有序的数据结构中。这里的数组从1下标开始存数据,代码如下:

          void InsertSort(int *arr,int len)

           {

                    int i,j;

                     for(i=2;i<=len;++i)

                     {

                           if(arr[i]<arr[i-1])

                            {

                                  arr[0]=arr[i];              //设置哨兵

                                  for(j=i-1;arr[j]>arr[0];j--)

                                  {

                                         arr[j+1]=arr[j];            //数据后移,循环结束,即找到了起始的要插入的数该插入的实际位置

                                  }

                                 arr[j+1]=arr[0];                 //将要插入的哨兵位数据插入对应位置

                            }

                     }

           }

         直接插入排序的时间复杂度为O(n2),即二次方。

        2. 堆排序

              堆分为大顶堆和小顶堆,每个结点的值都大于或等于其左右孩子结点的值,就称为大顶堆,或者每个结点的值均小于或等于其左右孩子结点的值,称为小顶堆。

              解决堆排序存在两个问题:(1)如何由一个无序序列构建一个堆;(2)如何利用一个大顶堆做升序排序,代码如下:

              void  HeapSort(int *arr,int len)

              {

                     int i;

                      for(i=len/2;i>0;i--)

                      {

                              HeapAdjust(arr,i,len);              //调整所有非叶子结点所在子树为大顶堆

                      }

                      for(i=len;i>1;i--)

                      {

                              swap(arr,1,i);                                //大顶堆的首个元素就是所有数中的最大值,所以每次只需要将arr[1]与最后一个元素交换,此后该位置的值不再变化

                              HeaoAdjust(arr,1,i-1);                  //交换之后,对剩下的1~i-1的下标数据调整为大顶堆

                      }

              }

              void HeapAdjust(char *arr,int sindex,int mindex)

              {

                       int tmp,j;

                       tmp=arr[sindex];                               //tmp保存当前根结点数值

                        for(j=2*sindex;j<=mindex;j*=2)       //j为i的左孩子结点

                        {

                                 if(j<m&& arr[j]<arr[j+1])           //如果左孩子下标在合理范围内并且左孩子数值小于右孩子数值

                                 {

                                         ++j;                                   //此时j记录的是左右孩子中数值较大的下标

                                 }

                                  if(tmp>=arr[j])                         //如果根结点的值比左右孩子中最大的值都大,则不需要做任何改变,跳出循环

                                  {

                                         break;

                                  }

                                  else

                                  {

                                          arr[sindex]=arr[j];              //如果根结点的值小于左右孩子中最大的值,则将左右孩子中最大的值赋值给根结点,

                                          sindex=j;                           //根结点下标变为原先左右孩子中较大值的下标

                                  }

                        }

                         arr[sindex]=tmp;                                //将新的根结点赋值成原来的根结点数值

              }

               堆排序的时间复杂度为O(nlog(n))。

           3.  归并排序

               思想:假设初始序列含有n个数值记录,则可以看成n个有序子序列,每个子序列长度为1,然后两两归并,直到得到一个完整的有序序列。代码如下:

                void MergeSort(int *arr,int len)

                {

                       Msort(arr,arr,1,len);

               }

              void Msort(int sr[],int tr1[],int s,int t)     //将sr[s.....t]归并排序为tr1[s....t]

              {

                    int mid;

                    int tr2[MAXSIZE+1];   //用来临时存放归并后的有序记录

                    if(s==t)

                    {

                           th1[s]=sr[s];

                    }

                    else

                     {

                             mid=(s+t)/2;

                            Msort(sr,tr2,s,m);     //将sr[s...m]归并为有序tr2[s....m]

                            Msort(sr,tr2,m+1,t);    //将sr[m+1...t]归并为有序tr2[m+1....t]

                            Merge(tr2,tr1,s,m,t);    //将tr2[s...m]和tr2[m+1.....t]合并为有序tr1[s....t]  

                     }

              }

              void Merge(int sr[],int tr[],int i,int m,int n)

              {

                       for(j=m+1,k=1;i<=m&&j<=n;k++)      // i为左半部分最左边下标,j为右半部分最左端下标,k表示最终合并排好序的tr数组的下标

                       {

                                if(sr[i]<sr[j])                            //如果整个最左端小,就将小的放入tr数组中

                                {

                                       tr[k]=sr[i++];

                                }

                                else

                                {

                                       tr[k]=sr[j++];         //否则,将sr[j]放入tr中,再让j后移

                                }

                       }

                        if(i<=m)                              //循环结束后,若是前半部分未放完,而后半部已完,则将前半部分剩余数据以此拷贝至tr数组中

                        {

                                 for(int x=0;x<=m-i;x++)

                                 {

                                          tr[k+x]=sr[i+x];

                                 }

                         }

                         

                        if(j<=n)                                       //循环结束后,若是后半部分未放完,而前半部已完,则将后半部分剩余数据以此拷贝至tr数组中

                        {

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

                                 {

                                          tr[k+x]=sr[j+x];

                                 }

                         }

              }

             归并排序时间复杂度为O(nlog(n)).

          4. 非递归的归并排序算法

             void MergeSort2(int arr[],int len)

             {

                    int *tr=(int *)malloc(sizeof(int)*len);

                    int k=1;

                    while(k<len)

                    {

                            MergePass(arr,tr,k,len);

                            k=2*k;         

                            MergePass(tr,arr,k,len);

                            k=2*k;    

                    }

             }

             void MergePass(int sr[],int tr[],int s,int n)

             {

                     int i=1;

                     int j;

                    while(i<=n-2*s+1)

                    {

                           Merge(sr,tr,i,i+s-1,i+2*s-1);

                           i=i+2*s;

                    }

                    if(i<n-s+1)

                    {

                           Merge(sr,tr,i,i+s-1,n);

                    }

                    else

                    {

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

                            {

                                   tr[j]=sr[j];

                            }

                    }

             }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值