总容易混淆的排序算法:直接选择、冒泡(鸡尾酒)、直接插入(二分插入)(希尔)

稳定不稳定看相等元素排序前和排序后的相对顺序是否改变。

O(n2)

直接选择(不稳定):选择出最小的放在第一位;选择出次小的放在第二位;……

代码:

#include <iostream>
using namespace std;
//直接选择排序算法描述:
/*
1、第一层遍历:以未排序的第一个元素作为最小值
2、第二层遍历:对剩下的未排序元素进行遍历,小于最小值则交换值
3、得到最小的元素组成排序序列,以此类推,第二小的元素也会排入到排序好的序列中。
4、重复直至排序完全
*/    //==》O(n^2)
void Swap08(int a[], int i,int j)
{
    int tmp;
    tmp=a[i];
    a[i]=a[j];
    a[j]=tmp;
}

void SelectSeq(int a[],int num)
{
    int min=0;
    for(int i=0;i<num-1;i++)    //最后一个序列是单独的一个元素,不需要再排序
    {
        min=i;//1、选择未排序序列的第一个值为最小的值
        for(int j=i+1;j<num;j++)  //遍历其余未排序的值,如果小于最小值,则交换值
        {
            if(a[i]>a[j])
                Swap08(a,i,j);
        }
    }
}

int main08()
{
    int a[]={12,8,20,5,9,16,7,30};
    int num=sizeof(a)/sizeof(a[0]);
    SelectSeq(a,num);
    for(int i=0;i<num;i++)
    {
        cout<<a[i]<<" ";
    }
    return 0;
}

 

冒泡(稳定):两两比较,最大的放后边;直到最大的放在末尾。

代码:

#include <iostream>
using namespace std;
//冒泡排序算法描述:
/*
1、比较相邻元素,如果前一个比后一个大,则交换位置。
2、对每一对相邻的元素做同样的工作,从第一对到最后一对,做完一次循环后,最后元素则是最大的。
3、针对以上元素重复以上步骤,除了最后一个。
4、重复对越来越少的元素做以上动作,直至没有可交换的对。
*/    //==》O(n^2)
void Swap09(int a[], int i,int j)
{
    int tmp;
    tmp=a[i];
    a[i]=a[j];
    a[j]=tmp;
}

void BubbleSeq(int a[],int len)
{
    for(int j=0;j<len-1;j++)
    {
        for(int i=0;i<len-1-j;i++)
        {
            if(a[i]>a[i+1])
                Swap09(a,i,i+1);
        }
    }
    return;
}

int main09()
{
    int a[]={12,8,20,5,9,16,7,30};
    int len=sizeof(a)/sizeof(a[0]);
    BubbleSeq(a,len);
    for(int i=0;i<len;i++)
    {
        cout<<a[i]<<" ";
    }
    return 0;
}

 

==》改进:鸡尾酒排序

代码:

#include <iostream>
using namespace std;
//鸡尾酒排序算法描述:
/*
1、设两个索引,一个索引第一位,一个索引最末尾。
2、单层循环,一遍最大冒泡,一次最小冒泡。
3、重复做以上动作,直到排序好。
*/    //==》O(n^2)

void Swap11(int a[], int i,int j)
{
    int tmp;
    tmp=a[i];
    a[i]=a[j];
    a[j]=tmp;
}
void CocktailSeq(int a[],int len)
{
    int left=0;
    int right=len-1;
    while(left<right)
    {
        for(int i=left;i<right;i++)
        {
            if(a[i]>a[i+1])
                Swap11(a,i,i+1);
        }
        right--;
        for(int j=right;j>left;j--)
        {
            if(a[j]<a[j-1])
                Swap11(a,j,j-1);
        }
        left++;
    }
    return; 
}

int main11()
{
    int a[]={12,8,20,5,9,16,7,30};
    int len=sizeof(a)/sizeof(a[0]);
    CocktailSeq(a,len);
    for(int i=0;i<len;i++)
    {
        cout<<a[i]<<" ";
    }
    return 0;
}

 

直接插入(稳定):拿到一张新牌,从后往前看;大于新牌,则往后移一位;小于或等于,则将新牌插入到后一位;

#include <iostream>
using namespace std;
//直接插入排序算法描述:
/*
1、第一层循环:拿到元素。
2、第二层循环:从该元素的前一个位置开始,一直向前循环,若大于拿到的元素,则向后移一位;若小于该元素,则把该元素插入到后面一位的位置上
3、重复做以上动作,直至最后一个元素也插好了。
*/    //==》O(n^2)
void InsertSeq(int a[],int len)
{
    for(int i=0;i<len;i++)
    {
        int tmp = a[i];
        int j=i-1;
        while(j>=0 && a[j] > tmp)
        {
            a[j+1]=a[j];
            j--;
        }
        a[j+1]=tmp;
    }
    return; 
}

int main()
{
    int a[]={12,8,20,5,9,16,7,30};
    int len=sizeof(a)/sizeof(a[0]);
    InsertSeq(a,len);
    for(int i=0;i<len;i++)
    {
        cout<<a[i]<<" ";
    }
}

 

==》改进1:二分插入排序(稳定)

代码:

#include <iostream>
using namespace std;
//直接插入排序的改进算法——二分查找定位插入算法描述:
/*
1、第一层循环:拿到元素。
2、二分法定位插入位置(插入改位置的后面)
3、把定位后右面的元素   从后往前    依次向后移动一位。
4、把拿到的元素插进去
*/    //==》O(n^2)
void DivInsertSeq(int a[],int len)
{
    for(int i=0;i<len;i++)
    {
        int tmp = a[i];
        int left=0;
        int right=i-1;
        while(left<=right)
        {
            int mid=(left+right)/2;
            if(a[mid]>tmp)
                right=mid-1;
            else
                left=mid+1;
        }
        for(int j=i-1;j>left;j--)
        {
            a[j+1]=a[j];
        }
        a[left]=tmp;
    }
    return; 
}

int main()
{
    int a[]={12,8,20,5,9,16,7,30};
    int len=sizeof(a)/sizeof(a[0]);
    DivInsertSeq(a,len);
    for(int i=0;i<len;i++)
    {
        cout<<a[i]<<" ";
    }
    return 0;
}

 

 ==》改进2:希尔排序(不稳定)

 

O(nlogn)

归并(稳定)

快排(不稳定)

堆排(不稳定)

 

点赞