十种常见排序算法及其C++实现

本文详细介绍了C++中的十种常见排序算法,包括冒泡排序、选择排序、插入排序等比较类排序,以及希尔排序、快速排序等非比较类排序,分析了它们的时间复杂度,并提供了相应的算法实现代码。
摘要由CSDN通过智能技术生成

1. 概述

十种常见排序算法可以分为以下两类

  1. 比较类排序:冒泡排序、选择排序、插入排序、希尔排序、快速排序、堆排序、归并排序
  2. 非比较类排序:桶排序、计数排序、基数排序、

2. 时间复杂度

在这里插入图片描述

3. 算法

3.1 冒泡排序

冒泡排序每次能够获取序列中的最大元素,并将其交换到正确位置

3.1.1 算法描述

  1. 从第一个元素开始,比较相邻元素,若左边的大于右边的,则交换两个元素
  2. 对所有相邻元素执行以上操作,从第一个到最后一个,从而将最大的元素交换到了最后
  3. 重复步骤二,除了比较最后一个元素
  4. 重复步骤1 2 3,获取正确序列

3.1.2 算法实现

void bubble_sort(vector<int> &nums)
{
    int len = nums.size();
    if (len >= 2)
    {
        for (int i = 0; i < len - 1; i++)
        {
            for (int j = 0; j < len - 1 - i; j++)
            {
                if (nums.at(j) > nums.at(j + 1))
                {
                    swap(nums.at(j), nums.at(j + 1));
                }
            }
        }
    }
}

3.2 选择排序

选择排序能够每次选中最大或最小的元素,将其交换到无序区的最后

3.2.1 算法描述

  1. 初始状态下,无序区集合为所有元素,有序区为空
  2. 第一次,从无序区选择最小(大)的元素,记录其位置location,将nums.at(location)放置到有序区的最后,并将该元素剔除出无序区
  3. 重复上述操作,直至有序区满,无序区为空

3.2.2 算法实现

void selection_sort(vector<int> &nums)
{
    int len = nums.size();
    for (int i = 0; i < len; i++)
    {
        int minLocation = i;
        for (int j = i; j < len; j++)
        {
            if (nums.at(j) < nums.at(minLocation))
            {
                swap(nums.at(j), nums.at(minLocation));
            }
        }
    }
}

3.3 插入排序

3.3.1 算法描述

  1. 初始状态,有序区中只有数组的第一个元素,无序区包含从第二个元素到最后一个元素
  2. 取出无序区的第一个元素,将该元素与有序区中的元素比较
  3. 从有序区最后一个元素开始比较,若该元素小于有序区最后的元素,将两者交换,记录该元素的新位置,继续与有序区其他元素进行比较
  4. 直到在有序区中找到一个位置,前一个元素小于新元素,后一个元素大于新元素,则此处为新元素的正确位置,终止循环
  5. 重复步骤2 3 4,直到无序区为空,则所有元素在有序区均已找到正确位置

3.3.2 算法实现

void insert_sort(vector<int> &nums)
{
    int len = nums.size();
    for (int i = 1; i < len; i++)
    {
        int temp = i;
        for (int j = i - 1; j >= 0; j--)
        {
            if (nums.at(temp) >= nums.at(j))
            {
                break;
            }
            else
            {
                swap(nums.at(temp), nums.at(j));
                temp = j;
                continue;
            }
        }
    }
}

3.4 希尔排序

3.4.1 算法描述

  1. 将待排序的数组元素分为若干个序列 T0+j1k, T1+j1k, … Ti+ji*k
  2. 选择一个增量序列 Ti, Ti+1k, Ti+2k, … Ti+jk,(i+jk<len)
  3. 对上述增量序列进行插入排序
  4. 改变序列的个数,重复2 3操作,直到只剩一个序列,则该数组已完成排序

3.4.2 算法实现

void shell_sort(vector<int> &nums)
{
    int len = nums.size();
    int loop = len / 2;
    while (loop >= 1)
    {
        for (int i = 0; i < loop; i++)
        {
            for (int j = 1; i + j * loop < len; j++)
            {
                int current = i + j * loop;
                for (int k = j; k > 0; k--)
                {
                    if (nums.at(current) > nums.at(i + (k - 1) * loop))
                    {
                        break;
                    }
                    else
                    {
                        swap(nums.at(current), nums.at(i + (k - 1) * loop));
                        current = i + (k - 1) * loop;
                    }
                }
                // print(nums);
            }
        }
        loop /= 2;
    }
}

3.5 快速排序

3.5.1 算法描述

  1. 选择一个数作为基准(一般为第一个)
  2. 将基准与其他数进行比较,比基准小的数放在左侧,比基准大的数放在右侧。该分区结束后,基准就位于它的正确位置,这个操作称为分区(partition)
  3. 对基准左侧和右侧的子序列执行分区操作

3.5.2 算法实现

void partition(vector<int> &nums, int start, int end)
{
    if (start >= end)
    {
        return;
    }
    int pivot = nums.at(start);
    int i = start, j = end;
    while (i != j)
    {
        while (i < j && nums.at(j) >= pivot)
        {
            j--;
        }
        while (i < j && nums.at(i) <= pivot)
        {
            i++;
        }
        if (i < j)
        {
            swap(nums.at(i), nums.at(j));
        }
    }
    swap(nums.at(i), nums.at(start));
    partition(nums, start, i - 1);
    partition(nums, i + 1, end);
}
void quick_sort(vector<int> &nums)
{
    int len = nums.size();
    partition(nums, 0, len - 1);
}

3.6 堆排序

3.6.1 算法描述

  1. 将初始待排序的数据构成一个大顶堆,获取无序区T[1,n]
  2. 将堆顶元素与最后一个元素进行交换,获取新的无序区T[1,n-1]
  3. 交换后的新的堆可能不满足大顶堆的性质,将T[1,n-1]构造成新的大顶堆
  4. 重复操作2 3,直至有序区满,无序区为空

3.6.2 算法实现

void getHeap(vector<int> &nums, int start, int end)
{
    if (end < start)
    {
        return;
    }
    int parent = (end - start + 1) / 2;
    for (int i = parent; i >= 0; i--)
    {
        if (2 * i + 1 <= end && nums.at(i) < nums.at(2 * i + 1))
        {
            swap(nums.at(i), nums.at(2 * i + 1));
        }
        if (2 * i + 2 <= end && nums.at(i) < nums.at(2 * i + 2))
        {
            swap(nums.at(i), nums.at(2 * i + 2));
        }
    }
    getHeap(nums, 2 * start + 1, end);
    getHeap(nums, 2 * start + 2, end);
}
void heap_sort(vector<int> &nums)
{
    int len = nums.size();
    for (int i = len - 1; i >= 0; i--)
    {
        getHeap(nums, 0, i);
        print(nums);
        swap(nums.at(0), nums.at(i));
    }
}

3.7 归并排序

3.7.1 算法描述

  1. 将一个长度为n的序列分割为两个长度为n/2的子序列
  2. 对两个子序列分别执行归并排序
  3. 将两个子序列合并成一个有序序列

3.7.2 算法实现

void merge(vector<int> &nums, int start, int end)
{
    if (start >= end)
    {
        return;
    }
    if (end - start == 1)
    {
        if (nums.at(start) > nums.at(end))
        {
            swap(nums.at(start), nums.at(end));
        }
        //print(nums);
        return;
    }

    int middle = (end - start) / 2 + start;
    merge(nums, start, middle);
    merge(nums, middle + 1, end);
    
    vector<int> current = nums;
    int i = start, j = middle + 1, k = start;
    while (i <= middle | j <= end)
    {
        if (i <= middle && j <= end)
        {
            if (nums.at(i) <= nums.at(j))
            {
                current.at(k) == nums.at(i);
                i++;
                k++;
                continue;
            }
            else
            {
                current.at(k) = nums.at(j);
                j++;
                k++;
            }
        }
        else if (i <= middle)
        {
            current.at(k) = nums.at(i);
            i++;
            k++;
        }
        else
        {
            current.at(k) = nums.at(j);
            j++;
            k++;
        }
        // print(current);
    }
    nums = current;
    //print(nums);
}
void merge_sort(vector<int> &nums)
{
    int len = nums.size();
    merge(nums, 0, len - 1);
}

3.8 桶排序

3.8.1 算法描述

  1. 设置一个指定大小的空桶(max - min) / 10+1
  2. 便利序列中的所有元素,将元素放入对应的空桶中(根据个位)
  3. 将非空桶中的元素进行排序
  4. 将所有非空桶中的元素进行拼接

3.8.2 算法实现

void bucket_sort(vector<int> &nums)
{
    int max = *max_element(nums.begin(), nums.end());
    int min = *min_element(nums.begin(), nums.end());
    int bucket = (max - min) / 10 + 1;
    vector<list<int>> vecBucket(bucket);
    for (int i = 0; i < nums.size(); i++)
    {
        vecBucket.at(nums.at(i) / 10).push_back(nums.at(i));
    }
    int temp = 0;
    while (temp < bucket)
    {
        for (auto &element : vecBucket)
        {
            element.sort();
        }
        temp++;
    }
    nums.clear();
    for (auto element : vecBucket)
    {
        for (auto data : element)
        {
            nums.push_back(data);
        }
    }
}

3.9 计数排序

3.9.1 算法描述

  1. 找出序列元素中的最大值和最小值,构造count(max-min+1)的数组
  2. 统计min~max之间的元素出现的次数,存入数组count
  3. 反向填充目标数组:count.at(i)=c,将i+min放入原始序列,c–

3.9.2 算法实现

void count_sort(vector<int> &nums)
{
    int min = *min_element(nums.begin(), nums.end());
    int max = *max_element(nums.begin(), nums.end());
    vector<int> count(max - min + 1, 0);
    for (int i = 0; i < nums.size(); i++)
    {
        count.at(nums.at(i) - min)++;
        // cout << nums.at(i) << " " << count.at(nums.at(i) - min) << " h" << endl;
    }
    // print(count);
    int location = 0;
    for (int i = 0; i < max - min + 1; i++)
    {
        int frequence = count.at(i);
        while (frequence != 0)
        {
            nums.at(location) = i + min;
            frequence--;
            location++;
        }
        // location += frequence;
    }
}

3.10 基数排序

3.10.1 算法描述

  1. 获取序列元素中的最大值,并获取该最大值的位数
  2. 从所有元素的个位开始,将个位相同的元素放入同一个数组base.at(i)中
  3. 将base数组中的所有元素按顺序放入原始数组中
  4. 对所有元素重复上述操作,十位、百位,直至最大值的位数,由此可以获得排好序的序列

3.10.2 算法实现

void base_sort(vector<int> &nums)
{
    int max = *max_element(nums.begin(), nums.end());
    int len = nums.size();
    int div = 1;
    vector<vector<int>> base(10);
    while ((max / div) % 10 != 0)
    {
        cout << (max / div) % 10 << endl;
        for (int i = 0; i < 10; i++)
        {
            base.at(i).clear();
        }
        for (int i = 0; i < len; i++)
        {
            int last = (nums.at(i) / div) % 10;
            base.at(last).push_back(nums.at(i));
        }
        int i = len - 1;
        while (i >= 0)
        {
            for (int j = 0; j < 10; j++)
            {
                while (!base.at(j).empty())
                {
                    cout << "base.at(" << j << "): ";
                    //print(base.at(j));
                    int current = base.at(j).back();
                    base.at(j).pop_back();
                    nums.at(i) = current;
                    i--;
                }
            }
        }
        //print(nums);
        div *= 10;
    }
}
  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值