排序算法:C++冒泡排序、选择排序、插入排序、希尔排序,快速排序,归并排序, 堆排序, 代码示例,效率对比

  1. 冒泡排序:每循环一次,对比前后两个数据,把大的挪到前面,所以循环一次最后一个是最大的元素,下次循环可以少循环一位

    void Bubble_sort(vector<int>& vect)
    {
        int size = vect.size();
        int N = size;
        int move_num = 0;
        int tem;
        for (int k = 0; k < size; k++)
        {
            N = size - k; // n,n-1,...,2,1
            move_num = 0;
            for (int i = 0; i < N-1; i++)  //注意是N-1
            {
                if (vect[i] > vect[i + 1])
                {
                    tem = vect[i];
                    vect[i] = vect[i + 1];
                    vect[i + 1] = tem;
                    move_num++;
                }
            }
            if(move_num==0)  //针对冒泡排序的优化,如果这次没有移动,说明已经排好了,break出去
                break;
        }
    }
    
  2. 选择排序:从头到尾扫描,找到最小的元素,和最前面的元素互换,下次从第二个开始

    所以理论上选择排序,遍历的次数多,但是最多交换n次,不像冒泡,可能要交换移动很多次

    void select_sort(vector<int>& vect)
    {
        int size = vect.size();
        if(size<2)
            return;
    
        int N=size;
        for(int i=0;i<size;i++)
        {
            N=size-i; //n,n-1,...1
            int max_id = N-1;
            for(int j=0;j<N-1;j++)
            {
                if(vect[j]>vect[max_id])
                {
                    max_id = j;  //最大的index
                }
            }
            //交换最大的和范围内最后一个
            int tem = vect[max_id];
            vect[max_id] = vect[N-1];
            vect[N-1]=tem;
        }
    }
    
  3. 插入排序:从第二个数开始,一直往前面对比,比他大,就后挪一个,直到不比它大,放到这,break出去。纸牌比喻

    void insert_sort(vector<int>& vect)
    {
        int size=vect.size();
        if(size<2)
            return;
        int tem = 0;
        for(int N=1;N<size;N++)  //1,2,...,n-1
        {
            tem = vect[N];
            int j=N-1;
            for(;j>=0;j--)
            {
                if(vect[j]>tem)
                {
                    vect[j+1]=vect[j];//后移一位
                }
                else
                {
                    break;
                }
            }
            vect[j+1]=tem;
        }
    }
    
  4. 希尔排序:相当于改进的插入排序,每间隔gap个分成一组进行插入排序,gap逐渐减小到1

    void shell_sort(vector<int>& vect)
    {
        int size=vect.size();
        if(size<2)
            return;
        
        for(int gap=size/2; gap>0; gap=gap/2)
        {
            //会有gap组,首个元素的索引分别是0,1,2,gap-1
            for(int start=0;start<gap;start++)  //首个元素的索引
            {
                int N=1;  //插入排序,从第二个开始
                while(start+N*gap<size)
                {
                    int tem=vect[start+N*gap];  //要插入排序的最后一个元素
                    int j=N-1;  //前一个开始
                    for(;j>=0;j--)
                    {
                        if(vect[start+j*gap]>tem)
                        {
                            vect[start+(j+1)*gap]=vect[start+j*gap];//后挪
                        }
                        else
                        {
                            break;
                        }
                    }
                    vect[start+(j+1)*gap]=tem;  //如果全部后移,j=-1; 否则就是j就是第一个比它小的
                    N++;
                }
            }
        }
    }
    
  5. 快速排序:每次取出一个元素,代码里是每次取出范围内第一个元素,把小于它的元素都放到左边,大于它的都放到右边,也就分割成了两部分,再对这两部分进行同样操作,所以可以用迭代实现,当左索引不小于右索引,停止迭代

    void fast_sort(vector<int>& vect, int L, int R)
    {
        if(L>=R)
            return;
        int left=L;
        int right=R;
        
        int elem = vect[left];  //取出最左边元素
        int LR=0; //0表示空位在左边,1表示空位在右边
        while(left<right)
        {
            if(LR==0)  //空位在左边
            {
                if(vect[right]<elem)
                {
                    vect[left]=vect[right];  //把右边小的放到空位
                    left++;  //left标记向右移动一位
                    LR=1;//空位变成了右边
                    continue;
                }
                else
                {
                    right--;
                    continue;
                }
            }
    
            if(LR==1)  //空位在右边
            {
                if(vect[left]>elem)
                {
                    vect[right]=vect[left];
                    right--;
                    LR=0;  //空位变成了左边
                    continue;
                }
                else
                {
                    left++;
                    continue;
                }
            }
        }
        //此时已经left=right是空位了
        vect[left]=elem;  //[L,left-1],left,[left+1,R]分成了两边的区间,左边的都小,右边的都大
        fast_sort(vect,L,left-1);
        fast_sort(vect,left+1,R);
    }
    
  6. 归并排序:两个排好序的数组合并成一个有序的数组,递归地把数组分成单个元素,再两两合并

    void Merge(vector<int> &VEC, int low, int mid, int high)
    {
        int start1 = low;  //[low,mid]
        int start2 = mid + 1;  //[mid+1, high]
        //存储临时排好序的
        vector<int> tem(high - low + 1, 0);
        int k = 0;
        
        while (start1 <= mid && start2 <= high)
        {
            if (VEC[start1] <= VEC[start2])
            {
                tem[k++] = VEC[start1++];
            }
            else
            {
                tem[k++] = VEC[start2++];
            }
        }
        //前半段还有剩余
        while (start1 <= mid)
        {
            tem[k++] = VEC[start1++];
        }
        //或者后半段还有剩余
        while (start2 <= high)
        {
            tem[k++] = VEC[start2++];
        }
        //把临时排好序的,插入原来序列
        k = 0;
        for (int i = low; i < high; i++, k++)
        {
            VEC[i] = tem[k];
        }
    }
    //归并排序
    void MergeSort(vector<int> &VEC, int low, int high)
    {
        // 终止递归的条件,子序列长度为1
        if (low >= high)
        {
            return;
        }    
        //先分,一直分到长度为1                             
        int mid = low + (high - low) / 2; // 取得序列中间的元素
        MergeSort(VEC, low, mid);         // 对左半边递归
        MergeSort(VEC, mid + 1, high);    // 对右半边递归
        //合并,把[low,mid] [mid+1, high]合并到一起
        Merge(VEC, low, mid, high);       
    }
    

    7.堆排序

    #include<queue>
    
    void heap_sort(vector<int> &vect)
    {
        priority_queue<int, vector<int>, greater<int>> min_heap;  //最小堆
        for (int i = 0; i < vect.size(); i++)
        {
            min_heap.emplace(vect[i]);
        }
        for (int i = 0; i < vect.size(); i++)
        {
            vect[i] = min_heap.top();
            min_heap.pop();
        }
    }
    

对比七种排序算法的时间效率
冒泡、选择、插入、希尔,快速, 归并, 堆排序, 越来越快

#include <iostream>
#include <vector>
#include <chrono>
#include <queue>
using namespace std;

//冒泡排序
void bubble_sort(vector<int> &vect);
//选择排序
void select_sort(vector<int> &vect);
//插入排序
void insert_sort(vector<int> &vect);
//希尔排序
void shell_sort(vector<int> &vect);
//快速排序
void fast_sort(vector<int> &vect, int L, int R);
//归并排序
void merge_sort(vector<int> &vect, int L, int R);
void merge(vector<int> &vect, int left, int mid, int right);
//堆排序
void heap_sort(vector<int> &vect);

int main()
{
    const int N = 100000;
    vector<int> VEC(N, 0);
    srand(time(0));
    for (int i = 0; i < N; i++)
    {
        VEC[i] = rand() % (N + 1);
    }
    vector<int> VEC1 = VEC;
    vector<int> VEC2 = VEC;
    vector<int> VEC3 = VEC;
    vector<int> VEC4 = VEC;
    vector<int> VEC5 = VEC;
    vector<int> VEC6 = VEC;
    //冒泡排序
    chrono::steady_clock::time_point t1 = chrono::steady_clock::now();
    bubble_sort(VEC1);
    chrono::steady_clock::time_point t2 = chrono::steady_clock::now();
    chrono::duration<double> time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
    cout << "冒泡排序: " << time_used.count() << " s" << endl;
    for (int i = 0; i < 30; i++)
        cout << VEC1[i] << " ";
    cout << endl;

    //选择排序
    t1 = chrono::steady_clock::now();
    select_sort(VEC2);
    t2 = chrono::steady_clock::now();
    time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
    cout << "选择排序: " << time_used.count() << " s" << endl;
    for (int i = 0; i < 30; i++)
        cout << VEC2[i] << " ";
    cout << endl;

    //插入排序
    t1 = chrono::steady_clock::now();
    insert_sort(VEC3);
    t2 = chrono::steady_clock::now();
    time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
    cout << "插入排序: " << time_used.count() << " s" << endl;
    for (int i = 0; i < 30; i++)
        cout << VEC3[i] << " ";
    cout << endl;

    //希尔排序
    t1 = chrono::steady_clock::now();
    shell_sort(VEC4);
    t2 = chrono::steady_clock::now();
    time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
    cout << "希尔排序: " << time_used.count() << " s" << endl;
    for (int i = 0; i < 30; i++)
        cout << VEC4[i] << " ";
    cout << endl;

    //快速排序
    t1 = chrono::steady_clock::now();
    fast_sort(VEC, 0, N - 1);
    t2 = chrono::steady_clock::now();
    time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
    cout << "快速排序: " << time_used.count() << " s" << endl;
    for (int i = 0; i < 30; i++)
        cout << VEC[i] << " ";
    cout << endl;

    //归并排序
    t1 = chrono::steady_clock::now();
    merge_sort(VEC5, 0, N - 1);
    t2 = chrono::steady_clock::now();
    time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
    cout << "归并排序: " << time_used.count() << " s" << endl;
    for (int i = 0; i < 30; i++)
        cout << VEC5[i] << " ";
    cout << endl;

    //堆排序
    t1 = chrono::steady_clock::now();
    heap_sort(VEC6);
    t2 = chrono::steady_clock::now();
    time_used = chrono::duration_cast<chrono::duration<double>>(t2 - t1);
    cout << "堆排序: " << time_used.count() << " s" << endl;
    for (int i = 0; i < 30; i++)
        cout << VEC6[i] << " ";
    cout << endl;

    return 0;
}

void bubble_sort(vector<int> &vect)
{
    int size = vect.size();
    int N = size;
    int move_num = 0;
    int tem;
    for (int k = 0; k < size; k++)
    {
        N = size - k; // n,n-1,...,2,1
        move_num = 0;
        for (int i = 0; i < N - 1; i++) //注意是N-1
        {
            if (vect[i] > vect[i + 1])
            {
                tem = vect[i];
                vect[i] = vect[i + 1];
                vect[i + 1] = tem;
                move_num++;
            }
        }
        if (move_num == 0) //针对冒泡排序的优化,如果这次没有移动,说明已经排好了,break出去
            break;
    }
}

void select_sort(vector<int> &vect)
{
    int size = vect.size();
    if (size < 2)
        return;

    int N = size;
    for (int i = 0; i < size; i++)
    {
        N = size - i; // n,n-1,...1
        int max_id = N - 1;
        for (int j = 0; j < N - 1; j++)
        {
            if (vect[j] > vect[max_id])
            {
                max_id = j;
            }
        }
        int tem = vect[max_id];
        vect[max_id] = vect[N - 1];
        vect[N - 1] = tem;
    }
}

void insert_sort(vector<int> &vect)
{
    int size = vect.size();
    if (size < 2)
        return;
    int tem = 0;
    for (int N = 1; N < size; N++) // 1,2,...,n-1
    {
        tem = vect[N];
        int j = N - 1;
        for (; j >= 0; j--)
        {
            if (vect[j] > tem)
            {
                vect[j + 1] = vect[j]; //后移一位
            }
            else
            {
                break;
            }
        }
        vect[j + 1] = tem;
    }
}

void shell_sort(vector<int> &vect)
{
    int size = vect.size();
    if (size < 2)
        return;

    for (int gap = size / 2; gap > 0; gap = gap / 2)
    {
        //会有gap组,首个元素的索引分别是0,1,2,gap-1
        for (int start = 0; start < gap; start++) //首个元素的索引
        {
            int N = 1; //插入排序,从第二个开始
            while (start + N * gap < size)
            {
                int tem = vect[start + N * gap]; //要插入排序的最后一个元素
                int j = N - 1;                   //前一个开始
                for (; j >= 0; j--)
                {
                    if (vect[start + j * gap] > tem)
                    {
                        vect[start + (j + 1) * gap] = vect[start + j * gap]; //后挪
                    }
                    else
                    {
                        break;
                    }
                }
                vect[start + (j + 1) * gap] = tem; //如果全部后移,j=-1; 否则就是j就是第一个比它小的
                N++;
            }
        }
    }
}

void fast_sort(vector<int> &vect, int L, int R)
{
    if (L >= R)
        return;
    int left = L;
    int right = R;

    int elem = vect[left];
    int LR = 0; // 0表示空位在左边,1表示空位在右边
    while (left < right)
    {
        if (LR == 0)
        {
            if (vect[right] < elem)
            {
                vect[left] = vect[right]; //把右边小的放到空位
                left++;                   // left标记向右移动一位
                LR = 1;                   //空位变成了右边
                continue;
            }
            else
            {
                right--;
                continue;
            }
        }

        if (LR == 1) //空位在右边
        {
            if (vect[left] > elem)
            {
                vect[right] = vect[left];
                right--;
                LR = 0;
                continue;
            }
            else
            {
                left++;
                continue;
            }
        }
    }
    //此时已经left=right是空位了
    vect[left] = elem;
    fast_sort(vect, L, left - 1);
    fast_sort(vect, left + 1, R);
}

void merge_sort(vector<int> &vect, int L, int R)
{
    if (L >= R)
        return;
    int mid = L + (R - L) / 2;
    //先把左右两边的排好序,再合并
    merge_sort(vect, L, mid);
    merge_sort(vect, mid + 1, R);
    merge(vect, L, mid, R);
}

void merge(vector<int> &vect, int left, int mid, int right)
{
    int id1 = left;
    int id2 = mid + 1;
    int k=0;
    vector<int> tem(right - left + 1, 0);
    while(id1<=mid && id2<=right)
    {
        if(vect[id1]<vect[id2])
        {
            tem[k]=vect[id1];
            id1++;
            k++;
        }
        else
        {
            tem[k]=vect[id2];
            id2++;
            k++;
        }
    }
    while(id1<=mid)
    {
        tem[k]=vect[id1];
        id1++; k++;
    }
    while(id2<=right)
    {
        tem[k]=vect[id2];
        id2++; k++;
    }
    k=0;
    for(;k<right-left+1;k++)
    {
        vect[left+k]=tem[k];
    }
}

void heap_sort(vector<int> &vect)
{
    priority_queue<int, vector<int>, greater<int>> min_heap;
    for (int i = 0; i < vect.size(); i++)
    {
        min_heap.emplace(vect[i]);
    }
    for (int i = 0; i < vect.size(); i++)
    {
        vect[i] = min_heap.top();
        min_heap.pop();
    }
}

结果

冒泡排序: 15.8883 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27 
选择排序: 3.63016 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27 
插入排序: 1.20537 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27 
希尔排序: 0.0167228 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27 
快速排序: 0.00830173 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27 
归并排序: 0.0135148 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27 
堆排序: 0.012091 s
0 0 1 4 4 4 5 9 10 10 11 11 13 13 13 15 15 16 18 18 19 20 20 21 23 23 24 26 27 27 

所以冒泡,选择,插入 越来越快,但是都比较慢
希尔,归并,堆排序,快速的效率越来越高. 快速最快
个人感觉快速排序(最快)的迭代代码可能比希尔还要好写一些
归并排序也很快,但是仍然没有快速排序快

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值