排序算法总结

各种排序算法:交换(冒泡,快速),

选择(直接选择,堆排序),

插入(直接插入,二分插入,希尔排序),

归并排序

1 冒泡排序

2 快速排序 (两种方法)

3 直接选择排序

4 堆排序

5 直接插入排序

希尔排序

二分法排序

6 归并排序

7 分配排序(基数排序,箱排序,计数排序) 没有实现


测试代码

各种算法的复杂度的一个总结

参考:排序算法实现及分析

=================================================================================

  1. 冒泡排序:就像气泡一样,当前元素和下一个比,合适就这样,不合适就交换折腾 n * n次


    //1 双重循环 ----里面的范围:[0,n-1-i] 比较的是j和j+1 2 每一次都要交换  3 优化代码,加上交换过标志 flag(若flag=false表示排好序);
    void sort_bubble( int arr[],int num )
    {
        bool flag=true;
        for(int i=0;i<num-1&&flag;i++)     //第 i趟循环: 总共是 n-1趟循环
        {
            flag=false;
                                                                                                                                                                                                                       
             //遇到 小(大)的数值往后面浮动,先把后面的i个已经排好序了:[0,num-i] [i,num](已经拍好了)
            for(int j=0;j<num-i;j++)     
            {
                if(arr[j]<arr[j+1])
                {
                    swap_element(arr+j,arr+j+1);
                    flag=true;
                }
            }
            /*printArray(arr,num);*/
        }
        printArray(arr,num);
    }


  2. 快速:元素找到自己的排序位置,当每个人都找到了,那个顺序就定了。


    //快速排序(冒泡法的改进:交换排序)    第一次调用 sort_Quick(arr,0,len)--- //一定要把pos隔离出来
    //做一趟 快速排序:arr[left] 的位置。
    int find_pos( int * arr, int left, int right )
    {
        int low=left,high=right;
        int tmp=arr[left];                //要找的 数值就保存在这里了,腾空一个位置。
        while(low<high)                   //结束的时候 low==high,也就是需要返回的 值所在的位置。
        {
            while(low<high&&arr[high]>tmp)
                high--;
            arr[low]=arr[high];             //把比较小的移动到 low端(或者直接调换顺序开个头)
            while(low<high&&arr[low]<tmp)
                low++;
            arr[high]=arr[low];           //把比较大的移动到high端
        }
        arr[low]=tmp;
        return low;
    }
    int find_pos2(int * arr, int left, int right)
    {
        int cmpValue = arr[right];
        int theIndex = left;
        for(int i = left; i < right; ++i)
        {
            if(arr[i] < cmpValue)
            {
                swap_element(arr+i,arr+theIndex);
                theIndex++;
            }
        }
        swap_element(arr+theIndex,arr+right);  //arr+theIndex是 大于等于arr+right的
        return theIndex;
    }
    void sort_quick( int arr[],int low,int high )
    {
        int pos;
        if(low<high)        //low==high的时候结束递归。
        {
            /*pos=find_pos(arr,low,high);*/
            pos=find_pos2(arr,low,high);
            sort_quick(arr,low,pos-1);     //左边的部分
            sort_quick(arr,pos+1,high);    //右边的部分
        }
    }



  3. 选择:老实的排序法,找到最值,和当前的位置进行交换。

    //1 每次取出来 最小的([i+1,n])  2 和当前的i进行交换(判断j和i是否相等)
    void sort_select( int arr[],int num )
    {
        int min;             //记录下 每一趟排序的 最小的那个下标。
        for(int i=0;i<num-1;i++)  //i 表示轮到了 哪一个下标的元素
        {
            min=i;
            for(int j=i+1;j<num;j++)
            {
                if(arr[j]<arr[min])
                {
                    min=j;
                }
            }
            //找到这一段的最小的值之后,与 arr[i]交换位置。
            if(i!=min)
            {
                swap_element(arr+i,arr+min);
            }
            printArray(arr,num);
        }
    }


  4. 堆:和选择一样建一个具有堆的性质二叉树(节点永远比子节点大),堆顶就是最值,拿出来,再建一次堆(i-1个)。


//从大到小(或者从小到大)排列:主要考虑的是 p(i) 以及  p.left(2*i-1)或者p.right(2*i)的较小或者较大值----然后交换或者退出
void siftdown( int arr[], int nodeN, int maxN)
{
    int tmp=arr[nodeN];
    int child=nodeN*2+1,parent=nodeN;
    while(child<=maxN)
    {
        if(child<maxN&&arr[child+1]<arr[child])  //存在右子树序列
        {
            child=child+1;                   //得到最小的结点。
        }
                                                                                                                                                                                          
        if(tmp<=arr[child]) break;
        else
        {
            arr[parent] = arr[child];
            parent = child;            //往 下面的层数进行扩展
            child = child*2+1;
        }
    }
    arr[parent]=tmp;
}
// 1 初建堆---符合堆的概念 [n....2],其中 根结点 arr[0]最小
//2 反复调整排序 [n....2]: 选择交换(arr[0],arr[n]),选取最(大)小的(arr[0]).
void sort_stack(int arr[],int num )
{
    for(int i=(num-1)/2;i>=0;i--)
    {
        siftdown(arr,i,num-1);
    }
                                                                                                                                                                                      
    cout<<"最小的元素是:"<<arr[0]<<endl;
    for(int n=num-1;n>=1;n--)
    {
        swap_element(arr,arr+n);
        siftdown(arr,0,n-1);
        printArray(arr,num);
    }
    printArray(arr,num);
}



5 插入排序

插入:随便拿一个向有序的中放。

开始只有找一个元素参照,一个必然是有序的,然后可以结合二分法查找,来排序,用查找的思想排序,逆天了


// 排列好的[1,i-1] 没有排列好的部分:[i,n]:只是 找到i这个位置和[1,i-1]比较和交换。
// 1 比较 2 移动(往后面移动),腾出位置来  3 插入到最后的一个位置。
void sort_insert( int arr[],int num )
{
    int curValue;
    int j;
    for(int i=0+1;i<num;i++)
    {
        curValue=arr[i];
        j=i-1;
        while(arr[j]>curValue&&j>=0)
        {
            arr[j+1]=arr[j];
            j--;
        }
        arr[j+1]=curValue;
        printArray(arr,num);
    }
}
void sort_Binaryinsert( int arr[],int num )
{
    int low,high,mid;
    int curValue;
    for(int i=0+1;i<num;i++)
    {
        curValue=arr[i];
        low=0;
        high=i-1;
                                                                                                                                                                          
        while(low<=high)             //结束条件:low=high+1(即为需要插入的位置); 1 2 4 5 6 3
        {
            mid=(low+high)/2;
            if(arr[mid]<curValue)
            {
                low=mid+1;
            }
            else
            {
                high=mid-1;
            }
        }
        //2 往后面移动和插入数值
        for(int j=i-1;j>=high+1;j--)
        {
            arr[j+1]=arr[j];
        }
        arr[high+1]=curValue;
        printArray(arr,num);
    }
}
//其实和 直接插入排序 大致相同,只是间隔gap换成 1就可以了
void sort_shellComplete( int arr[], int num, int gap )
{
    int curValue;
    int j;
    for(int i=0+gap;i<num;i++)
    {
        curValue=arr[i];
        /*j=i-gap;
        while(arr[j]>curValue&&j>=0)
        {
            arr[j+gap]=arr[j];
            j-=gap;
        }*/
        for(j=i-gap;j>=0&&arr[j]>curValue;j=j-gap)
        {
            arr[j+gap]=arr[j];
        }
        arr[j+gap]=curValue;
        printArray(arr,num);
    }
}
void sort_shell( int arr[],int num )
{
    for(int i=num/2;i>=1;i=i/2)
    {
        sort_shellComplete(arr,num,i);
    }
}


6 归并:几组有序的合并成一个。很简单,每人轮流拿出一个比较下,放进篮子里不就完了。


void merges( int arr[], int low, int mid, int high )
{
    //前半部分:[low,mid]   后半部分:[mid+1,high]  然后分别比较→赋值(再移动即 循环)
    int i=low,j=mid+1,k=low;               //i,j两个坐标的变化;k--新的组成的数组的下标的变化--  k=0错误
    int tmparr[50];
    while(i<=mid&&j<=high)       //结束条件就是:其中一个条件不满足(其中一个已经用完了)
    {
        if(arr[i]<arr[j])
        {
            tmparr[k++]=arr[i++];
        }
        else
        {
            tmparr[k++]=arr[j++];
        }
    }
    //好好处理一下的部分
    while(i<=mid)
    {
        tmparr[k++]=arr[i++];
    }
    while(j<=high)
    {
        tmparr[k++]=arr[j++];
    }
    //合并好的 数组元素付给 需要合并的数组。
    for(int i=low;i<=high;i++)
    {
        arr[i]=tmparr[i];
    }
}
void sort_ReMerge( int arr[], int low, int high )
{
    int mid;
    if(low<high)               //最后: 单个的元素(low==high) 结束递归。
    {
        mid=(low+high)/2;
        sort_ReMerge(arr,low,mid);        //前半段分
        sort_ReMerge(arr,mid+1,high);     //后半段分
        merges(arr,low,mid,high);          //前后 两段合并
    }
}
void sort_merge( int arr[],int num)
{
    sort_ReMerge(arr,0,num-1);
    printArray(arr,num);
}



测试代码

void printArray(int arr[],int num)
{
    cout<<"排序后的数组元素是:"<<endl;
    for(int i=0;i<num;i++)
    {
        cout<<arr[i]<<endl;
    }
}


void swap_element(int *a,int *b)
{
    int tmp;
    tmp=*a;
    *a=*b;
    *b=tmp;
}


int main()
{
                                                                                                                                                      
    int arr[]={101,87,25,90,54,21,99,27,76};
    int num=sizeof(arr)/sizeof(int);
    printArray(arr,num);
    //sort_bubble(arr,num);
    //sort_quick(arr,0,num-1);
    //sort_select(arr,num);
    //sort_insert(arr,num);
    //sort_shell(arr,num);
    //sort_Binaryinsert(arr,num);
    //sort_stack(arr,num);
    //sort_merge(arr,num);
    return 0;
}

====================================================================================

各种算法的复杂度的一个总结


直接选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,

而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。



最好 最坏 平均 稳定 辅助空间

快速排序 O(nlogn) O(n^2) O(nlogn) 否 不要

冒泡排序 O(n) O(n^2) O(n^2) 是 不要

直接选择排序 O(n^2) O(n^2)O(n^2) 否 不要

堆排序 O(nlogn) O(nlogn) O(nlogn) 否 不要

直接插入排序 O(n) O(n^2) O(n^2) 是 不要

希尔排序 O(n) O(n^2) O(n^2) 否 不要

归并排序 O(nlogn) O(nlogn) O(nlogn) 是 要(1.5?)


你可能感兴趣的:(排序,面试)