【总结】经典排序算法(C++)

最近在学习算法,趁这个机会总结一些算法。慢慢更新,欢迎交流探讨。

参考书籍:《算法导论》

排序:

输入:n个数

输出:有序(从大到小、从小到大)序列

一、插入排序

做排序的都需要做遍历,而插入排序,顾名思义,就是插队。

不必多说,给个案例体会一下:

输入:5 4 3 2 1

处理

  •    4 5 3 2 1
  •    3 4 5 2 1
  •    2 3 4 5 1
  •    1 2 3 4 5

输出:1 2 3 4 5

 

输入:6 8 2 4 5

处理

  • 6 8 2 4 5
  • 2 6 8 4 5
  • 2 4 6 8 5
  • 2 4 5 6 8

代码如下(测试):

(排序部分第11-16行);

input:输入数组元素数n;输入数组元素a[i];输入n=0代码结束;

#include<iostream>
#include<string.h>
using namespace std;
int main()
{
    int n,key,i,j,a[100];
    while (cin>>n,n!=0)
    {
        for(int i=0;i<n;i++)
        cin>>a[i];
        for(int j=1;j<n;j++)
        {
            key=a[j];
           for(i=j-1;i>=0&&a[i]>key;i--)
               a[i+1]=a[i];
            a[i+1]=key;
        }
        for(int k=0;k<n;k++)
        {
            cout<<a[k]<<" ";
        }
        cout<<endl;
    }
}

二、选择排序:

规则:首先找到数组的最小数,与a[0]交换;循环下去,找到第n小的数,与数组的第n个数交换;

案例

    输入: 5 4 9 8 3

    处理

  • 3 4 9 8 5
  • 3 4 9 8 5
  • 3 4 5 8 9
  • 3 4 5 8 9

输出:3 4 5 8 9

代码如下:

#include<iostream>
using namespace std;
int main()
{
    int n,a[100],key,x;
    while(cin>>n,n!=0)
    {
        for(int i=0;i<n;i++)
            cin>>a[i];
        for(int i=0;i<n;i++)
    {
       key=a[i];
       x=i;
       for(int j=i+1;j<n;j++)
       {
           if(a[j]<key)
           {
               key=a[j];
               x=j;
           }
       }
       int tem=a[i];
       a[i]=a[x];
       a[x]=tem;
    }
    for(int i=0;i<n;i++)
        cout<<a[i]<<" ";
    }
}

三、归并排序(MERGE SORT)

规则:将原数组分解成n个子序列,再对子序列递归地进行排序。其中,单个元素被视为是已经排列好的。

说明:这个算法在下根据课本先做了两个函数,第一个是做对数组的分割,其次是对数组的排序;而在主函数中,用了srand产生100以内的随机数。

案例:

输入:5 2 4 7 1 3 2 6

处理:分割:5     2    4    7    1    3    2    6

           合并:2 5    4 7    1 3     2 6  

           再合并:2 4 5 7    1 2 3 6

           再合并:1 2 3 4 5 6 7

代码如下:

#include <iostream>
#include <time.h>
#include <stdlib.h>
using namespace std;

void Merge(int *_Array, int p, int q, int r) {// p:第0个;r:第n-1个数,q:第(r + p) / 2个数
    int len1 = q - p + 1;
    int len2 = r - q;
    int *L = new int[len1 + 1];//用动态数组储存左边的数
    int *R = new int[len2 + 1];//用动态数组储存右边的数

    for (int i = 0; i < len1; i++) {// 把Array数组左边的数放入L数组
        L[i] = _Array[p + i];
    }

    for (int j = 0; j < len2; j++) {// 把Array数组右边的数放入R数组
        R[j] = _Array[q + 1 + j];
    }
    L[len1]=R[len2]=INT_MAX;    //定义无穷大
    int i = 0, j = 0;
    for (int k = p; k <= r; k++) {
        if (L[i] < R[j]) {//小的放左边,大的放右边
            _Array[k] = L[i];
            i++;
        }
        else {
            _Array[k] = R[j];
            j++;
        }
    }
}

void MergeSort(int _Array[], int p, int r) {
    if (p < r) {//p:第0个;r:第n-1个数。数组至少要有两个数据
        int q;
        q = (r + p) / 2;//拆分两组
        MergeSort(_Array , p , q);//拆分第0个到第 (r + p) / 2个 ,即拆分左半部分
        MergeSort(_Array , q+1 , r);//拆分第(r + p) / 2个到第r个 ,即拆分右半部分
        Merge(_Array , p , q , r);//调用合并函数,从第0个到第n-1个排好
    }
}

int main() {
    int n;
    cout<<"请输入数组的元素数:";
    cin >> n;
    cout << endl;
    int *Array = new int[n];
    cout << "随机数组为:";
    srand((unsigned)time(0));

    for (int i = 0; i < n; i++) {
        Array[i] =  (rand()%(100-0+1))+0;
        //cin>>;
        cout<<Array[i]<<"  ";
    }
    cout<<endl;

    MergeSort(Array,0,n-1);

    cout << "排序后的数组为:";
    for(int j  = 0;j<n;j++){
        cout<<Array[j]<<"  ";
    }
    return 0 ;
}

 

四、快速排序法

  • 介绍:

       快速排序的最坏情况(输入数从小到大或从大到小)的运行时间为cita(n^2),但快速排序是用于排序的最佳实用选择,因为其平均性能相当好,一般的运行时间为cita(nlgn),且cita(nlgn)中的常数因子很小。此外,快速排序还可以就地排序,在虚存环境中也能很好运行。

        同归并排序类似地,快速排序也是基于分治法的,

  • divide 分解:将数组A[p....r]划分为两个子数组A[p..q-1]和A[q...r]排序,使得A[p...q-1]<=A(q)<=A[q+1...r]
  • conquer解决:通过递归调用Quicksort,对子数组A[p...q-1]和A[q...r]排序。
  • combine.合并:此步可忽略,因为A[p...r]已经排序。
  • 原理:

  • 案例:(来自算法导论)仅partition部分:

代码如下:

#include<iostream>
#include<time.h>
#include<stdlib.h>
using namespace std;
int Partition(int *a,int p,int q)        //函数:使得<x的数在X的左边,>x的数在x的右边
{
    int x=a[p];
    int i=p;
    for(int j=p+1;j<=q;j++)
    {
        if(a[j]<=x)
        {
            i++;
            int temp=a[i];
            a[i]=a[j];
            a[j]=temp;
        }
    }
    int temp=a[i];
    a[i]=a[p];
    a[p]=temp;
    return i;
    }
void QuickSort(int *a,int p,int q)
{
    if(p<q)            //递归停止的信号p>=q
    {
        int r=Partition(a,p,q);
        QuickSort(a,p,r-1);
        QuickSort(a,r+1,q);
    }
}
int main()
{
    int n;
    cout<<"请输入";
    cin >> n;
    cout << endl;
    int *Array = new int[n];
    cout << "产生的随机数组为:";
    srand((unsigned)time(0));
    for (int i = 0; i < n; i++) {
        Array[i] =  (rand()%(100-0+1))+0;
        cout<<Array[i]<<"  ";
    }
    cout<<endl;

    QuickSort(Array,0,n-1);

    cout << "排序后的数组为:";
    for(int j  = 0;j<n;j++){
        cout<<Array[j]<<"  ";
    }
    return 0;
}

快速排序的最佳情况运行时间为cita(nlgn);

快速排序的最坏情况运行时间为cita(n^2)   //即是划分得不平衡,如划分为n-1与1;

,而插入排序的最坏情况运行时间为cita(n),这时候快速排序真是徒负虚名。这归咎于我们选取的x的位置被固定住了,所以下面的随机快速排序就是一种优化。

五、随机快速排序

作为一种优化,其实也是用一个随机种子生产随机数,随机抽取某一个数做为x,再调用partition函数,仅仅加了一个函数,再做一点点修改,代码如下:

#include<iostream>
#include<time.h>            //添加文件
#include<stdlib.h>
using namespace std;
int Partition(int *a,int p,int q)
{
    int x=a[p];
    int i=p;
    for(int j=p+1;j<=q;j++)
    {
        if(a[j]<=x)
        {
            i++;
            int temp=a[i];
            a[i]=a[j];
            a[j]=temp;
        }
    }
    int temp=a[i];
    a[i]=a[p];
    a[p]=temp;
    return i;
    }
int Random_Partition(int* a,int p,int q)    //产生随机数做下标,使得中间数是随机的数
{
    int i=rand()%(q-p)+0;
    int temp=a[i];
    a[i]=a[q];
    a[q]=temp;
    return Partition(a,p,q);
}
void QuickSort(int *a,int p,int q)
{
    if(p<q)
    {
        int r=Random_Partition(a,p,q);
        QuickSort(a,p,r-1);
        QuickSort(a,r+1,q);
    }
}
int main()
{
    int n;
    cout<<"请输入";
    cin >> n;
    cout << endl;
    int *Array = new int[n];
    cout << "产生的随机数组为:";
    srand((unsigned)time(0));
    for (int i = 0; i < n; i++) {
        Array[i] =  (rand()%(100-0+1))+0;
        cout<<Array[i]<<"  ";
    }
    cout<<endl;

    /*cout<<"请输入数组:"<<endl;
    for(int i=0;i<n;i++)
        cin>>Array[i];*/
    QuickSort(Array,0,n-1);
    cout << "返回的下标为:"<<Partition(Array,0,n-1)<<endl;
    cout << "排序后的数组为:";
    for(int j  = 0;j<n;j++){
        cout<<Array[j]<<"  ";
    }
    delete []Array ;
    return 0;
}

六、计数排序法

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
void Counting_Sort(int *a,int *b,int n,int *c,int m)
{
    for(int i=0;i<m;i++)
        c[i]=0;
    for(int j=0;j<n;j++)
        c[a[j]]++;
    for(int i=1;i<m;i++)
        c[i]+=c[i-1];
    for(int j=n-1;j>=0;j--)
    {
        b[c[a[j]]-1]=a[j];
        c[a[j]]--;
    }
}
int main()
{
    int n,m;
    cout<<"input an number as the size of the matrix:"<<endl;
    cin>>n;
    cout<<"input the largest number you hope:"<<endl;
    cin>>m;
    int *a = new int[n];
    int *b = new int[n];
    int *c = new int[m];
    cout<<"here is the matrix:"<<endl;
    srand((unsigned)time(0));
    for(int i=0;i<n;i++)
    {
        a[i]=rand()%(m+1)+0;
        cout<<a[i]<<" ";
    }
    cout<<endl;
    /*写成函数。。
    for(int i=0;i<m;i++)//注意这些循环的界限
        c[i]=0;
    for(int j=0;j<n;j++)
        c[a[j]]++;
    for(int i=1;i<m;i++)
        c[i]+=c[i-1];
    for(int j=n-1;j>=0;j--)
    {
        b[c[a[j]]-1]=a[j];
        c[a[j]]--;
    }*/
    Counting_Sort(a,b,n,c,m);
    cout<<"and the result is:"<<endl;
    for(int i=0;i<n;i++)
        cout<<b[i]<<" ";
    cout<<endl;
    delete []a;                 //new之后最好delete掉
    delete []b;
    delete []c;
}

七、基数排序法

#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int GetMax(int a[],int n)
{
    int max=a[0];
    for (int i=0;i<n;i++)
        max= a[i]>max?a[i]:max;
    return max;
}
void CountingSort(int a[],int n,int exp)
{
    int b[n]={0};
    int c[10]={0};
    for(int i=0;i<n;i++)
        c[(a[i]/exp)%10]++;
    for(int i=1;i<10;i++)
        c[i]+=c[i-1];
    for(int j=n-1;j>=0;j--)
    {
        b[c[(a[j]/exp)%10]-1]=a[j];
        c[(a[j]/exp)%10]--;
    }
    for(int i=0;i<n;i++)
        a[i]=b[i];
}
void RadixSort(int a[],int n)
{
    int exp;
    int max=GetMax(a,n);
    for(exp=1;max/exp>0;exp*=10)
        CountingSort(a,n,exp);
}
int main()
{
    int n,m;
    cout<<"please input a numb as the length of matrix:"<<endl;
    cin>>n;
    cout<<"please input the largest numb you hope:"<<endl;
    cin>>m;
    int *a = new int [n];
    srand((unsigned)time(0));
    for(int i=0;i<n;i++)
    {
        a[i]=rand()%m;
        cout<<a[i]<<" ";
    }cout<<endl;
    RadixSort(a,n);
    for(int i=0;i<n;i++)
    {
        cout<<a[i]<<" ";
    }cout<<endl;
    delete []a;
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章