排序模板

排序数组下标都是从1开始的

一、插入类排序

直接插入排序

时间复杂度:n^2       稳定性:稳定   辅助空间: O(1)

void InsertSort()
{
    int i,j;
    for(i=2;i<=n;i++)
    {
        a[0]=a[i];
        j=i-1;
       while(a[0]<a[j]&&j>0)     //a[i]是到第i个数为止的排序
       {
           a[j+1]=a[j];
           j--;
       }
        a[j+1]=a[0];  //大于他的是后是插在他后面,所以是j+1
    }
}

折半插入排序

时间复杂度 n^2      稳定性:稳定     辅助空间: O(1)

优化了一些

void BInsertSort()
{
   int i,j;
   for(i=2;i<=n;i++)
   {
      a[0]=a[i];
      int left=1;
      int right=i-1;
      while(left<=right)
      {
          int mid=(left+right)/2;
          if(a[0]>a[mid])
          left=mid+1;
          else
          right=mid-1;
      }
      for(j=i-1;j>=left;j--)
      a[j+1]=a[j];
      a[left]=a[0];
   }
}

希尔排序

时间复杂度:n^1.5       稳定性: 不稳定    辅助空间: O(1)

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
#define MAXN 1000
int n;
int a[MAXN];
void ShellInsert(int delta)
{
    int i,j;
    for(i=1+delta;i<=n;i++)
    {
            a[0]=a[i];
            j=i-delta;
            while(a[0]<a[j]&&j>0)
            {
                a[j+delta]=a[j];
                j-=delta;
            }
            a[j+delta]=a[0];
    }
}
int main()
{
    int i;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    scanf("%d",&a[i]);
    int delta=floor(n/2);
    while(delta>0)
    {
      ShellInsert(delta);
      delta/=2;
    }
    for(i=1;i<=n;i++)
    printf("%d ",a[i]);
    return 0;
}

 

 

 

二、交换类排序

 

冒泡排序

时间复杂度:n^2       稳定性: 稳定   辅助空间: O(1)

void BubbleSort()
{
      for(j=1;j<n;j++)         //   j是比较次数
      for(i=1;i<=n-j;i++)   //i是确保存在倒数第二个a[],i,j都是从1开始的,反正就是小的数。
      if(a[i]>a[i+1])          //大的沉底就从小到大排序,小的沉底就由大到小排序
      {
      t=a[i];
      a[i]=a[i+1];
      a[i+1]=t;
      } 

}

快速排序

时间复杂度:nlog2n   稳定性:不稳定   辅助空间: O(log2n)

void  QuickSort(int left,int right)
{
    int i,j,t;
    if(left<right)
    {
       i=left+1;  //i是从left+1开始的
       j=right;
       while(1)
       {
         while(i<=n&&a[i]<a[left])
         {
             i++;
         }
         while(j>=1&&a[j]>a[left])
         {
             j--;
         }
         if(i>=j)
         break;
         else
         {
            t=a[i];
            a[i]=a[j];
            a[j]=t;
            i++,j--;
         }
       }
       t=a[left],a[left]=a[j],a[j]=t;  //本来ij都可以,但考虑不交换的情况,只有j吻合
       QuickSort(left,j-1);
       QuickSort(j+1,right);
    }
}

快速排序的另一种方法

int QKPass(int low,int high)
{
    int x=a[low];
    while(low<high)
    {
        while(low<high&&a[high]>=x) high--;
        if(low<high)  {a[low]=a[high]; low++;}
        while(low<high&&a[low]<x)  low++;
        if(low<high)  {a[high]=a[low]; high--;}
    }
    a[low]=x;
    return low;
}
void QuickSort(int low,int high)
{
    int pos;
    if(low<high)
    {
        pos=QKPass(low,high);
        QuickSort(low,pos-1);
        QuickSort(pos+1,high);
    }
}

三、选择类排序

 

直接选择排序

时间复杂度:n^2;       稳定性: 不稳定    辅助空间: O(1)

void SelectSort()
{
    int i,j;
    for(i=1;i<=n-1;i++)    //到倒数第二个数就好
    {
        int k=i;                  //只需要一个临时空间存这个待比较的数
        for(j=i+1;j<=n;j++)
        {
            if(a[j]<a[k])
            k=j;
        }
        if(k!=i)                  //其实这个判断不必要,感觉,写起来只不过看的严谨些
        {
            int t;
            t=a[i];
            a[i]=a[k];
            a[k]=t;
        }
    }
}



树形排序

时间复杂度: nlog2n  

 

struct Node
{
    int Data;
    int Index;
    int Active;             //Active 用来出里空结点与不能再参与比较的结点
}Tree[MAXN];
int n;
int cnt; //记录层数
int a[MAXN];
//更新不能用初次构建的那种方法,两者不一样
void UpdateTree(int id)
{
    int j;
   //从叶子结点的调整
   if(id%2==1)
   Tree[id/2]=Tree[id-1];   //id是奇数在右边
   else
   Tree[id/2]=Tree[id+1];
   id=id/2;
   //叶子结点上层的调整
   while(id)                //直到 i==0
  {
     if(id%2==1)
     j=id-1;
     else
     j=id+1;
     //存在Active==0的情况
     if(Tree[id].Active==0||Tree[j].Active==0)
     {
       if(Tree[id].Active==1)
       Tree[id/2]=Tree[id];        //i可参选, i上
       else
       Tree[id/2]=Tree[j];   	 //否则, j上
     }
     else		                   //两方都可参选
    {
      if(Tree[id].Data<=Tree[j].Data )
      Tree[id/2]=Tree[id];        	//关键码小者上
      else
      Tree[id/2]=Tree[j];
    }
    id=id/2;
  }
}
void TreeSort()
{
    int BottomRowSize=pow(2,1.0*(cnt-1));  //利用层数算出底层叶节点个数
    int TreeSize=2*BottomRowSize-1;        //总结点个数
    int LoadIndex= BottomRowSize-1;        //内结点个数
    int i;
    int j=1;
    //初始化
    for(i=LoadIndex+1;i<=TreeSize;i++)
    {
       Tree[i].Index=i;
       if(j<=n)
       {
           Tree[i].Active=1;
           Tree[i].Data=a[j++];  //已知的叶子结点 1.赋值 2.Active 标记为1
       }
       else
       Tree[i].Active=0;
    }
    //第一次选出胜者
    i=LoadIndex+1;                //进行初始比较选择最小的项
    while(i)
    {
        j=i;
        while(j<2*i)             //这里是小于2*i,<或<=每一次都套下验证
        {
            if(Tree[j+1].Active==0||Tree[j].Data<=Tree[j+1].Data)
            Tree[j/2]=Tree[j];             //这种是三个属性一起转移的
            else
            Tree[j/2]=Tree[j+1];
            j+=2;
        }
        i=i/2;  //i每次只记录最左边那个位置。
    }
    a[1]=Tree[1].Data;
    for(i=2;i<=n;i++)
    {
        Tree[Tree[1].Index].Active=0;    //失去参选资格
        UpdateTree(Tree[1].Index);      //进行剩下的n-1次更新
        a[i]=Tree[1].Data;                  //这样就是从小到大排序了
    }
}
int main()
{
    scanf("%d",&n);
    cnt=ceil(log2(n))+1; //cnt用来记录层数
    int i;
    for(i=1;i<=n;i++)
    scanf("%d",&a[i]);
    TreeSort();
    for(i=1;i<=n;i++)
    printf("%d ",a[i]);
    return 0;
}

 

堆排序

 

时间复杂度:nlog2n    稳定性:不稳定   辅助空间: O(1)

void Sift(int k,int m)             //没次筛的是以a[k]为根的完全二叉树
{
    int t=a[k];
    int i=k;                //k是不能改变的
    int j=2*i;
    int flag=0;
    while(j<=m&&flag==0)
    {
        if(j+1<=m&&a[j]<a[j+1])   //j+1<=n是判断有无右子树,另一个是挑左右子树大的那个
        j+=1;
        if(t>=a[j])
        flag=1;
        else
        {
            a[i]=a[j];
            i=j;
            j=2*i;            //因为要不断向下延伸,能不*2吗?
        }
    }
    a[i]=t;
}
void Create_Heap()
{
    int i;
    for(i=n/2;i>=1;i--)
    Sift(i,n);
}
void HeapSort()
{
    int i;
    Create_Heap();
    for(i=n;i>=2;i--)  //最后一个元素不用再调
    {
        int t=a[1];
        a[1]=a[i];
        a[i]=t;
        Sift(1,i-1);
    }
}

四、归并排序

 

时间复杂度:nlog2n      稳定性:稳定     辅助空间: O(n)

void Merge(int l,int mid,int r)
{
     int i=l,j=mid+1,k=l;//i是最左边的那个数,j是中间偏右的第一个数,这样也是对称比较 明白两个数,三个数的交换就行。
     while(i<=mid&&j<=r)             //像两链表合并的感觉
    {
        if(a[i]<=a[j])
        {
            rrr[k]=a[i];
            k++;
            i++;
        }
        else
        {
            rrr[k]=a[j];
            k++;
            j++;
        }
    }
    while(i<=mid)
        rrr[k]=a[i],k++,i++;
    while(j<=r)
        rrr[k]=a[j],k++,j++;
    for(int i=l;i<=r;i++)
        a[i]=rrr[i];        //重新赋值的操作
}
void MergeSort(int l,int r)
{
     if(r==l) return;
     int mid=(l+r)/2;
     MergeSort(l,mid);
     MergeSort(mid+1,r);
     Merge(l,mid,r);
}


五、分配类排序

基数排序

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define MAXN 10010
int a[MAXN];
int bit_max=0;
int n;
void get_bit()
{
    int i;
    for(i=1;i<=n;i++)
    {
        int cnt=1;
        int temp=a[i];
        while(temp/10!=0)
        {
            temp/=10;
            cnt++;
        }
        bit_max=max(bit_max,cnt);
    }
}
void radixsort()
{
    get_bit();
    int num=1;
    int i,j,k,p,q;
    int Count[MAXN];
    int temp[10][MAXN];
    for(i=1;i<=bit_max;i++)
    {
      memset(Count,0,sizeof(Count));
      memset(temp,0,sizeof(temp));
      for(j=1;j<=n;j++)
      {
        k=(a[j]/num)%10;
        Count[k]++;
        temp[k][Count[k]]=a[j];
      }
      p=1;
      for(j=0;j<=9;j++)
      {
          if(Count[j]>0)
          {
              for(q=1;q<=Count[j];q++)
              {
                  a[p]=temp[j][q];
                  p++;
              }
          }
       }
       num*=10;
    }
}
int main()
{

    scanf("%d",&n);
    int i;
    for(i=1;i<=n;i++) scanf("%d",&a[i]);
    radixsort();
    for(i=1;i<n;i++) printf("%d ",a[i]);
    cout<<a[i]<<endl;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值