排序模板

排序数组下标都是从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;
}

 

### 冒泡排序算法模板代码 冒泡排序是一种简单的排序算法,它重复遍历要排序的列表,依次比较相邻元素并按需要交换它们的位置。这个过程会持续进行直到不需要再做任何交换为止。 以下是用 C 语言编写的冒泡排序算法的一个典型实现: ```c #include <stdio.h> // 定义冒泡排序函数 void bubbleSort(int arr[], int n) { int i, j; for (i = 0; i < n-1; i++) // 最后 i 个元素已经是最大的,在每次迭代之后已经就位 for (j = 0; j < n-i-1; j++) if (arr[j] > arr[j+1]) { // 如果前一个元素大于后一个,则交换两者位置 int temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } // 测试冒泡排序功能 int main() { int a[10] = {1, 9, 6, 3, 5, 7, 1}; // 初始化待排序数组[^1] printf("原始数组: "); for (int k=0; k<7; ++k){ printf("%d ",a[k]); } bubbleSort(a, 7); // 调用冒泡排序函数对数组进行排序[^2] printf("\n排序后的数组: "); for (int k=0; k<7; ++k){ printf("%d ",a[k]); } return 0; } ``` 此程序定义了一个 `bubbleSort` 函数用于执行实际的排序操作,并通过调用该函数演示如何使用它来对一组数据进行排序。这段代码展示了完整的流程,包括初始化数组、打印未排序的数据集、应用排序方法以及展示已排序的结果[^3]。 #### 关键特性解释: - **双重循环结构**:外层循环控制整个过程运行次数;内层循环负责逐次对比每一对邻近项。 - **条件判断与交换机制**:当发现左边数值较大时即刻与其右边邻居互换位置,从而使得较大的数逐渐向右移动直至到达正确的地方。 - **优化空间**:虽然这里给出的是最基础版本,但在实践中可以通过设置标志变量提前终止不必要的后续扫描以提高效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值