挑战程序设计(算法和数据结构)—排序

插入排序

稳定排序
O(N^2)
将未排序的头元素插入到已排序的元素中
特点:高速处理顺序较平整的数组,希尔排序的基础

void InsertSort(int a[], int N)
{
    for(int i=1; i<N; i++)#i循环变量,表示未排序的开头元素下标
    {
        int v = a[i];#保存当前元素的值
        int j= i-1;
        while(j>=0 && a[j]>v)#j循环变量,用于在已排序部分寻找v的插入位置
        {
            a[j+1] = a[j];#相应元素后移
            j--;
        }
        a[j+1] = v;#插入到合适位置
    }
}
冒泡排序

稳定排序
O(N^2)
每一轮在未排序区比较相邻元素,筛选出最小元素到排序区尾

void BubbleSort(int a[], int N)
{
     int flag = 1, i = 0;#flag标记当前轮是否存在交换,若没有则结束排序。i表示未排序区的开头元素标记,从数组开头向末尾移动
     while(flag)
     {
         flag = 0;
         for(int j=N-1; j>i; j--)#对于未排序部分中相邻元素两两比较,从N-1开始,减少到i+1结束
         {
             if(a[j]<a[j-1])#每轮比较相邻元素
             {
                 int temp = a[j];
                 a[j] = a[j-1];
                 a[j-1] = temp;
                 flag = 1;
                 Count++;
             }
         }
         i++;
     }
}
选择排序

不稳定排序
O(N^2)
在未排序区选出最小元素,放入已排序区尾

void SelectSort(int a[], int N)
{
      for(int i=0; i<N-1; i++)#i表示未排序部分的开头元素,从数组开头向末尾移动
      {
          int minj = i;#在各轮循环处理中,未排序区的最小元素的下标
          for(int j=i+1; j<N; j++)#用来查找未排序部分中最小值的位置
          {
              if(a[j] < a[minj])
                minj = j;
          }
          if(i!=minj)#可以交换
          {
              int temp = a[i];
              a[i] = a[minj];
              a[minj] = temp;
              Count++;
          }
      }
}
希尔排序

O(N^1.25)
不同间隔的插入排序,最后一定以1为间隔来一次插入排序
特点:比较次数多,交换次数少

vector<int> G;#间隔序列
void InsertSort(int a[], int N, int g)#以g为间隔的插入排序
{
    for(int i=g; i<N; i+=g)
    {
        int v = a[i];
        int j= i-g;
        while(j>=0 && a[j]>v)
        {
            a[j+g] = a[j];
            j-=g;
            cnt++;
        }
        a[j+g] = v;
    }
}

void ShellSort(int a[], int N)
{
       //生成G序列
       int h  = 1;
       while(h<N)
       {
           G.push_back(h);
           h = h*3+1;
       }

       for(int i=G.size()-1; i>=0; i--)#重复G序列次
       {
           InsertSort(a, N, G[i]);
       }
}
归并排序

O(Nlog(N)) (O(log(N))为分割,O(N)为归并)
稳定
特点:高效且稳定,但要占用额外的内存空间(除了输入数据)。

void Merge(int S[], int left, int right, int mid)//归并(归并时比较排序)
{
    int n1 = mid-left, n2 = right-mid;//以mid为界限,分割为两个数组
    for(int i=0; i<n1; i++)
    {
        a[i] = S[i+left];
        //Count++;
    }
    for(int i=0; i<n2; i++)
    {
        b[i] = S[i+mid];
        //Count++;
    }
    a[n1] = M, b[n2] = M;//确保最后一个数较大,利于以下排序(M超出了S中元素的范围)
    int k=left, ka=0, kb=0;
    //Count++;
    while(k<right)
    {
        if(a[ka]>b[kb])//升序排列,一定为大于,保证了稳定排序
        {
            S[k++] = b[kb++];
        }
        else
        {
            S[k++] = a[ka++];
        }
        Count++;//计数
    }
}

void MergeSort(int S[], int left, int right)//用于分割数组,分别排序(分治)
{
    if(left+1<right)//判断是否可以分割
    {
        int mid = (left+right)/2;
        MergeSort(S, left, mid);
        MergeSort(S, mid, right);
        Merge(S, left, right, mid);//归并
    }
}
快速排序

O(Nlog(N))(平均)O(N^2)(最坏)
不稳定
特点:内部排序,不占用额外内存。技巧在于基准x的选择(随机选择、任选几个取其平均)。

void swap(int *x, int *y)//交换函数
{
    int temp = *x;
    *x = *y;
    *y = temp;
}
int Partition(int A[], int p, int r)//分割函数(每次排好一个元素的位置)
{
    int x = A[r];//分割的标准,大于x 的为一部分,其余的为另一部分
    int i=p-1;//下标小于等于i的元素不大于x
    for(int j=p; j<r; j++)
    {
        if(A[j].n<=x.n)
        {
            i++;
            swap(A[i], A[j]);
        }
    }
    swap(A[i+1], A[r]);//将A[r]即x移为分割位置,此即其排序的位置
    return i+1;
}

void quickSort(Card A[], int p, int r)//快排
{
    if(p<r)
    {
        int q = Partition(A, p, r);
        quickSort(A, p, q-1);
        quickSort(A, q+1, r);
    }
}
计数排序

O(n+k)(n是排序数组的长度,k是计数数组的长度,即排序数组中最大值)
稳定
特点:线性时间排序,所用时间和空间均与原数组的最大值成正比。

int A[MaxA], B[MaxB], C[MaxC];
//A原数组。C计数数组m,C[i]表示小于等于i的A中元素的个数。B排序后的数组。
void CountingSort(int A[], int n, int k)
{
    memset(C, 0, sizeof(C));//初始化为0
    for(int i=0; i<n; i++)//计算值为A[i]的元素的个数
    {
        C[A[i]]++;
    }
    for(int i=1; i<=k; i++)//计算值小于等于i的元素的个数
    {
        C[i] += C[i-1];
    }
    for(int i=n-1; i>=0; i--)//倒序(保证稳定排休)
    {
        B[C[A[i]]] = A[i];//注意:输出B时,要从1到n输出,因为C[A[i]](1-n)表示小于等于A[i]的元素的个数,其值一定大于0
        C[A[i]]--;
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值