c++经典算法汇总

来源:互联网 发布:dnf制裁知乎 编辑:程序博客网 时间:2024/05/17 08:04


排序方法最好时间平均时间最坏时间辅助空间稳定性冒泡O(n)O(n^2)O(n^2)O(1)稳定直接选择O(n^2)O(n^2)O(n^2)O(1)不稳定鸡尾酒O(n)O(n^2)O(n^2)O(1)稳定直接插入O(n)O(n^2)O(n^2)O(1)稳定希尔 O(n^1.25) O(1)不稳定快速排序O(nlgn)O(nlgn)O(n^2)O(nlgn)不稳定归并排序O(nlgn)O(nlgn)O(nlgn)O(n)稳定堆O(nlgn)O(nlgn)O(nlgn) 不稳定计数排序O(n)O(n)O(n) 稳定

冒泡排序

经过n-1趟子排序,第i趟子排序从第1个数至第n-i个数,若第i个数比后一个数大(则升序,小则降序)则交换两数

O(n^2)

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;        b = c;}void bublesort(int a[],int n){    for (int i=0 ; i<n ; i++)        for (int j=0 ; j a[j+1])                swap(a[j],a[j+1]);        }}int main(){    int a[]={10,5,2,7};    bublesort(a,4);    for (int i=0;i<4;i++)        cout << a[i]<<" ";    return 0;}

不足1:在排序过程中,执行完最后的排序后,虽然数据已全部排序完备,但程序无法判断是否完成排序,为了解决这一不足,可设置一个标志单元flag,将其设置为OFF,表示被排序的表示是一个无序的表。在每一排序开始时,检查此标志,若此标志为0,则结束排序;否则进行排序;

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void bublesort(int *a,int n){    int flag;    for(int i=0;i<n;i++)    {        while(flag)        {            flag=0;            for (int j=0 ; j a[j+1])                {                    swap(a[j],a[j+1]);                    flag=1;                }            }            for (int i=0;i<n;i++)                cout << a[i]<<" ";            cout << endl;        }    }}int main(){    int a[]={10,3,2,5,7};    bublesort(a,5);        return 0;}

不足2:当排序的数据比较多时排序的时间会明显延长。改进方法:快速排序

选择排序

每一趟从无序数列元素中选出最小(或最大)的一个元素,顺序放在有序数列的最后,直到全部待排序的数据元素排完。

O(n^2)

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void selectsort(int a[],int n){    int min,i,j;    for (i=0;i<n;i++)    {        min=i;        for(j = i+1;j<n;j++)            if(a[j]<a[min])                min=j;        swap(a[i],a[min]);    }}int main(){    int a[]={10,5,2,7};    selectsort(a,4);    for (int i=0;i<4;i++)        cout << a[i]<<" ";    return 0;}

鸡尾酒排序

即定向冒泡排序,先对数组从左到右进行升序的冒泡排序,再对数组进行从右到左的降序的冒泡排序,如此往复

O(n^2)

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void shaker(int a[],int n){    int top=n,bottom=0;    int i,j;    bool flag=true;    while (flag)     {            flag = false;            for (i = bottom; i < top; i++)                 if (a[i] > a[i + 1])                 {                    swap(a[i], a[i+1]);                    flag = true;                }            top--;            for (j = top; j > bottom; j--)                 if (a[j] < a[j - 1])                 {                    swap(a[j], a[j - 1]);                    flag = true;                }            bottom++;    }}int main(){    int a[]={10,5,2,7};    shaker(a,4);    for (int i=0;i<4;i++)        cout << a[i]<<" ";    return 0;}

直接插入排序

每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成为止。

O(n^2)

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void insertsort(int *a,int n){    int j,i,k;    for (i=1;i=0;j--)            if(a[j]=0;k--)                a[k+1]=a[k];            a[k+1]=temp;        }    }}int main(){    int a[]={10,3,2,5,7};    insertsort(a,5);    for (int i=0;i<5;i++)        cout << a[i]<<" ";    return 0;}

由于代码太长,现在进行改写,将搜索和数据后移这二个步骤合并

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void insertsort(int *a,int n){    int j,i;    for (i=1;i<n;i++)        if(a[i]=0&&a[j]>temp;j--)                a[j+1]=a[j];            a[j+1]=temp;        }}int main(){    int a[]={10,3,2,5,7};    insertsort(a,5);    for (int i=0;i<5;i++)        cout << a[i]<<" ";    return 0;}

另一种更简便的方法,如果a[i]<a[i-1],就一直交换,直到a[i]>a[i-1]

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void insertsort(int *a,int n){    int i,j;    for (i=1;i=0&&a[j]>a[j+1];j--)            swap(a[j],a[j+1]);}int main(){    int a[]={10,3,2,5,7};    insertsort(a,5);    for (int i=0;i<5;i++)        cout << a[i]<<" ";    return 0;}

希尔排序

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

O(n^1.25))

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void shellsort(int a[],int n){    int i,j,k,gap;    for(gap=n/2;gap>0;gap/=2)        for ( i=0;i<gap;i++)            for(j=gap+i;j<n;j++)                if(a[j]=0 && a[k]>temp)                    {                        swap(a[k+gap],a[k]);                        k-=gap;                    }                    a[k+gap]=temp;                }}int main(){    int a[]={10,3,2,5,7};    shellsort(a,5);    for (int i=0;i<5;i++)        cout << a[i]<<" ";    return 0;}

现在对该代码进行改进,从原先的一组比完比第二组,改进到比较第一组的前两个数,再比较第二组的前两个数。。。在比较第一组的2、3两个数,再比较第二组的2、3两个数,一次类推

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void shellsort(int a[],int n){    int i,k,gap;    for(gap=n/2;gap>0;gap/=2)        for(i=gap;i<n;i++)            if(a[i]=0 && a[k]>temp)                {                    swap(a[k+gap],a[k]);                    k-=gap;                }                a[k+gap] = temp;            }}    int main(){    int a[]={10,3,2,5,7};    shellsort(a,5);    for (int i=0;i<5;i++)        cout << a[i]<<" ";    return 0;}

现在使用直接插入排序中的改善代码3进行边比较边移位的代码优化

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void shellsort(int a[],int n){    int i,j,gap;    for(gap=n/2;gap>0;gap/=2)        for(i=gap;i=0 && a[j]>a[j+gap];j-=gap)                swap(a[j],a[j+gap]);}int main(){    int a[]={10,3,2,5,7};    shellsort(a,5);    for (int i=0;i<5;i++)        cout << a[i]<<" ";    return 0;}

快速排序

首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面

O(nlgn)

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void quicksort(int a[],int l,int r){    int i=l,j=r;    int symbol=a[l];   //以第一个数做基准    if(i>j)        return;    while(i<j)    {        while(isymbol)            j--;        if(i<j)            a[i++]=a[j];   //a[i]=a[j],i++        while(i<j && a[i]<symbol)            i++;        if(i<j)            a[j--]=a[i];    }    a[i]=symbol;    quicksort(a,l,i-1);    quicksort(a,i+1,r);}//第二种排序算法(些许变化,供参考)void quicksort2(int a[],int l,int r){     int i = l;     int j = r;     int key = a[(i+j)/2];     while(i < j)        {            for(;(i < r)&&(a[i] < key);i++);            for(;(j > l)&&(a[j] > key);j--);            if (i <= j)               {                   swap(a[i],a[j]);                   i++;                   j--;                }        }     if (i < r)           quicksort(a,i,r);     if (j > l)           quicksort(a,l,j);}int main(){    int a[]={10,3,2,5,7};    quicksort(a,0,5);    for (int i=0;i<5;i++)        cout << a[i]<<" ";    return 0;}

归并排序

把待排序序列分为若干个子序列,每个子序列是有序的(递分解)。然后再把有序子序列合并为整体有序序列(合新序列)。

O(nlgn)

#includeusing namespace std;void merge(int a[], int first, int last, int temp[]);void mergearray(int a[], int first, int mid, int last, int temp[]);bool mergesort(int a[], int n){    int *temp = new int[n];    if (temp == NULL)        return false;    merge(a, 0, n - 1, temp);    return true;}void merge(int a[], int f, int l, int temp[]){    if (f < l)    {        int mid = (f+ l) / 2;        merge(a, f, mid, temp);         merge(a, mid + 1, l, temp);         mergearray(a, f, mid, l, temp); //有序数列合并    }}void mergearray(int a[], int f, int mid, int l, int temp[]){    int i = f , j = mid + 1,k = 0;    while (i <= mid && j <= l)    {        if (a[i] < a[j])            temp[k++] = a[i++];        else            temp[k++] = a[j++];    }    while (i <= mid)        temp[k++] = a[i++];    while (j <= l)        temp[k++] = a[j++];    for (i = 0; i < k ; i++)        a[f+i] = temp[i];}int main(){    int a[]={10,3,2,5,7};        mergesort(a,5);    for (int i=0;i<5;i++)        cout << a[i]<<" ";    return 0;}

堆排序

建立一个(最小/最大)堆H[0..n-1],把堆首和堆尾互换,把堆的尺寸缩小1,并调用filterdown( ),目的是把新的数组顶端数据调整到相应位置,直到堆的尺寸为1

O(nlgn)

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void heapfilterdown(int a[],int i,int n){    int j=i*2+1;   //节点的左孩子    int temp=a[i];    while(j<n)    {        if(j+1a[j])            j++;        if(a[j]=0;i--)  //找到对数组最后一个节点的父节点,对应数组需要-1        heapfilterdown(a,i,n);}void heapsort(int a[],int n){    makeminheap(a,n);               //排列成最小堆    for(int i=n-1 ; i>0;i--)           {        swap(a[0],a[i]);            //堆顶元素与堆底元素交换        heapfilterdown(a,0,i);      //向下排列,形成最大堆    }}int main(){    int a[]={10,5,2,7};    heapsort(a,4);    for (int i=0;i<4;i++)        cout << a[i]<<" ";         //输出为递增函数,如果需输出递减函数,使用最小堆    return 0;}

计数排序

  1. 找出待排序的数组中最大和最小的元素 2、统计数组中每个值为i的元素出现的次数,存入数组C的第i项 3、对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加) 4、反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1

O(n)

#includeusing namespace std;inline void swap(int &a,int &b){    int c = a;    a = b;    b = c;}void countsort(int a[] , int n){    int z=0;    int min,max;    min=max=a[0];    for(int i=0;imax)            max=a[i];        if(a[i]<min)            min=a[i];    }    int clength=max+min+1;                    //创建一个max+min+1大小的辅助数组    int *c = new int[clength];    for (int i=0 ; i<clength;i++)        c[i]=0;    for(int i=0;i<n;i++)                    //将待排数组每一个元素个数记录在对应的辅助数组中        c[a[i]-min]++;    for(int i=min ;i<=max;i++)        for(int j=0;j<c[i-min];j++)          //从小到大遍历辅助数组放入原数组,排序完成            a[z++]=i;    delete[] c;}int main(){    int a[]={10,3,2,5,7};    countsort(a,5);    for (int i=0;i<5;i++)        cout << a[i]<<" ";    return 0;}