c++常用排序方法

1.桶排序

桶排序(Bucket Sort)是一种分布式排序算法,其基本思想是将待排序的数组分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是递归使用桶排序),最后将各个桶中的元素按照顺序合并。

桶排序算法的一般步骤如下:

  1. 确定桶的数量:首先确定桶的数量,这通常取决于待排序数组的大小和元素的范围。

  2. 初始化桶:创建一个数组,每个元素是一个空的列表或队列,这些列表或队列将作为桶。

  3. 分配元素:遍历待排序数组,将每个元素分配到一个桶中。分配的规则可以是元素值除以桶的数量取余,或者根据元素的值范围分配到相应的桶。

  4. 对每个桶进行排序:对每个桶中的元素进行排序。如果桶中的元素数量不多,可以使用简单的排序算法,如插入排序;如果桶中的元素数量较多,则可以使用更高效的排序算法。

  5. 合并桶:一旦所有桶都排序完成,将它们按照顺序合并。这通常涉及到将每个桶的元素依次取出并放入一个新的数组中。

桶排序代码自取:

#include <iostream>
using namespace std;
int main()
{ 
    int n, x, a[6] = {};// 数组大小根据题目更改
    cin >> n;
    // 把待排序数字存储到有序"桶"内
    for (int i = 1; i <= n; i++)
    {
        cin >> x;
        a[x]++;
    }
    // 按顺序从"桶"内取出数字
    for (int i = L; i <= R; i++)// L和R表示待排序元素的大小范围
    {
        for (int j = 1; j <= a[i]; j++)// 通过循环控制数字输出次数
       {
            cout << i << " ";
       }
   }
    return 0;
}

        当然,桶排虽然简单易懂,效率但很大程度上取决于元素的分布和桶的数量。如果元素分布均匀,桶排序可以非常高效,时间复杂度可以达到 O(n+k),其中 n 是待排序数组的元素数量,k 是桶的数量。然而,如果元素分布不均匀,某些桶可能会包含大量元素,导致排序效率降低。

以下重点!!! 

桶排序适用于以下情况:

  • 数据量较大且数据分布比较均匀。
  • 数据范围已知且可以合理分配到桶中。

桶排序不适用于:

  • 数据分布极不均匀,导致某些桶中的元素数量过多。
  • 桶的数量难以确定或桶的初始化成本过高。

由于照顾有人只会桶排(但应该不多,毕竟大家都是大佬),于是乎,我这为大家提供两种去重方法

1.1.桶排序去重方法一 :

  • 桶排序通常用于将数据分布到有限数量的桶中,每个桶可以看作是一个计数器。
  • 在这个简化的例子中,数组 a 被用作桶,其索引代表输入数字的值,而数组中的值表示相应数字出现的次数。
  • 通过将每个输入数字的计数加1,我们可以统计每个数字出现的次数。
  • 在输出阶段,我们只打印那些在数组 a 中计数不为0的数字,这样就能去除重复的数字。

实现代码自取:

#include <iostream>
using namespace std;
int main()
{ 
    int n, x, a[6] = {};// 数组大小根据题目更改
    cin >> n;
    // 把待排序数字存储到有序"桶"内
    for (int i = 1; i <= n; i++)
   {
        cin >> x;
        a[x]++;
   }
    // 按顺序从"桶"内取出数字
    int L=0,R=5;//L为0,R为5,以确保能够正确遍历整个数组
    for (int i = L; i <= R; i++)// L和R表示待排序元素的大小范围
   {
        if (a[i] != 0)// if语句只输出一次  
       {
            cout << i << " ";
       }
   }
    return 0;

}

1.2.去重方法二 

 跟方法一差不多,就循环不一样,且看注释理解吧(属实不知怎么讲(ಥ_ಥ) )

代码:

#include <iostream>
using namespace std;
int main()
{ 
    int n, x, a[6] = {};// 数组大小根据题目更改
    cin >> n;
    // 把待排序数字存储到有序"桶"内
    for (int i = 1; i <= n; i++)
   {
        cin >> x;
        a[x] = 1;// 多次输入的数字只统计一次
   }
    // 按顺序从"桶"内取出数字
    for (int i = L; i <= R; i++)// L和R表示待排序元素的大小范围
   {
        for (int j = 1; j <= a[i]; j++)// 通过循环控制数字输出次数
       {
            cout << i << " ";
       }
   }
    return 0;
}

2.冒泡排序

冒泡排序的基本思路如下:

  1. 开始排序:从数列的第一个元素开始,比较相邻的两个元素。

  2. 比较和交换:如果左边的元素比右边的元素大,则交换它们的位置。这样一轮下来,最大的元素会被放到数列的最后。

  3. 重复遍历:然后对除了最后一个元素之外的所有元素重复上述过程。每一轮结束,都会将次大的元素放到倒数第二个位置。

  4. 减少比较次数:随着排序的进行,已经排序好的元素位于数列的后面,不需要再参与比较,所以每一轮的比较次数可以逐渐减少。

  5. 结束条件:当进行一轮遍历没有发生任何交换时,说明数列已经完全排序完成。

冒泡排序的步骤可以概括为:

  • 假设有一组数列:[5, 3, 8, 4, 2]
  • 第一轮:
    • 比较5和3,交换位置:[3, 5, 8, 4, 2]
    • 比较5和8,不交换
    • 比较8和4,交换位置:[3, 5, 4, 8, 2]
    • 比较8和2,交换位置:[3, 5, 4, 2, 8]
  • 第二轮:
    • 比较3和5,不交换
    • 比较5和4,交换位置:[3, 4, 5, 2, 8]
    • 比较5和2,交换位置:[3, 4, 2, 5, 8]
  • 第三轮:
    • 比较3和4,不交换
    • 比较4和2,交换位置:[3, 2, 4, 5, 8]
  • 第四轮:
    • 比较3和2,交换位置:[2, 3, 4, 5, 8]
  • 此后,数列已经排序完成,不再需要进行更多轮次的比较。

#include <iostream>
using namespace std;
void BubbleSort(int a[], int n)
{
    // 遍历n-1个数字
    for (int i = 1; i <= n - 1; i++)
   {
        // 遍历[1,n-i],因为每排序一趟之后就有一个数字不需要再进行比较
        for (int j = 1; j <= n - i; j++)
       {
            // 不满足大小关系则进行交换
            // 从小到大:a[j] > a[j + 1] 从大到小:a[j] < a[j + 1]
            if (a[j] > a[j + 1])
           {
                swap(a[j], a[j + 1]);
           }
       }
   }
    return ;
}
int main()
{
    int n, a[101] = {};
    cin >> n;
    // 存储待排序数字
    for (int i = 1; i <= n; i++)
   {
        cin >> a[i];
   }
    // 用函数封装冒泡关键代码
    BubbleSort(a, n);
    // 输出排序后的结果
    for (int i = 1; i <= n; i++)
   {
        cout << a[i] << " ";
   }
    return 0;
}

冒泡排序的时间复杂度为 O(n^2),在小规模数据或基本有序的数据集中效率相对较高。然而,对于大规模数据集,它的效率通常不如其他更高级的排序算法,如快速排序、归并排序或堆排序。

 又由于照顾有人只会冒泡排序(应该不多,毕竟大家都是大佬),又于是乎,我这里再次提供冒泡排序优化方法

2.1.冒泡排序优化

直接看代码:

#include <iostream>
using namespace std;
void BubbleSort(int a[], int n)
{
    // 遍历n-1个数字
    for (int i = 1; i <= n - 1; i++)
   {
        bool flag = true;// flag标记是否产生交换
        // 遍历[1,n-i],因为每排序一趟之后就有一个数字不需要再进行比较
        for (int j = 1; j <= n - i; j++)
       {
            // 不满足大小关系则进行交换
            // 从小到大:a[j] > a[j + 1] 从大到小:a[j] < a[j + 1]
            if (a[j] > a[j + 1])
           {
                swap(a[j], a[j + 1]);
                flag = false;// 产生交换则标记
           }
       }
        if (flag) // 如果是true说明排序完成
       {
            break;//结束冒泡排序
       }
   }
    return ;
}
int main()
{
    int n, a[101] = {};
    cin >> n;
    // 存储待排序数字
    for (int i = 1; i <= n; i++)
   {
        cin >> a[i];
   }
    // 用函数封装冒泡关键代码
    BubbleSort(a, n);
    // 输出排序后的结果
    for (int i = 1; i <= n; i++)
   {
        cout << a[i] << " ";
   }
    return 0;
}

3.选择排序

选择排序是一种简单的排序算法,其工作原理是分多次从待排序的数据中选取最小(或最大)的元素,然后将该元素放到已排序序列的末尾。这个算法是不稳定的,也就是说相同的元素在排序后可能会改变它们原来的顺序。以下是选择排序算法的基本步骤:

  1. 找到最小值:在未排序的序列中找到最小(或最大)的元素。

  2. 交换元素:将找到的最小元素与未排序序列的第一个元素交换。

  3. 移动边界:将未排序序列的边界向前移动,排除已经排序的元素。

  4. 重复过程:从新的未排序序列中重复步骤1-3,直到所有元素都被排序。

选择排序算法的特点是不管数组原来的排列顺序如何,每次都是取未排序部分的最小值与最开始的位置交换,这样保证了每一轮都能确定一个元素的最终位置。

以下是选择排序的实现示例:

#include<iostream>
using namespace std;
void Selsort (int a[], int n)
{
    for (int i = 0; i < n - 1; i++)
    {
        int min = i;//假设第i个值为最小值
        for (int j = i + 1; j < n; j++)//遍历从i+1到n-1的所有元素
     {
            if (a[j] < a[min])//打擂台找最小值
            {
                min = j;
        }
    }
        if (min != i)
           swap(a[i],a[min]);//交换最小值与下标为i的元素的值
    }
}
int main()
{
    int n, a[1000];
    cin >> n;
    for (int i = 0; i < n; i++)
     {
        cin >> a[i];
    }
    Selsort(a,n);
    for (int i = 0; i < n; i++)
     {
         cout << a[i] << " ";
    }
    return 0;
}

选择排序的时间复杂度是O(n^2),空间复杂度是O(1),这使得它在数据量较小或者对内存使用有限制的情况下是一个可行的选择。然而,对于大型数据集,由于其较低的效率,通常不推荐使用选择排序。 

3.1.选择排序的简化写法

我个人觉得以上代码太多了,不容易记,于是乎,我将其化简了一下

上代码:


#include<iostream>
using namespace std;
void Selsort (int a[], int n)
{
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = i + 1; j < n; j++)//遍历从i+1到n-1的所有元素
     {
            if (a[i] < a[j])//打擂台找最小值
            {
                swap(a[i], a[j]);
        }
    }
    }
}
int main()
{
    int n, a[1000];
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    Selsort(a,n);
    for (int i = 0; i < n; i++)
    {
        cout << a[i] << " ";
    }
    return 0;
}

4.插入排序

插入排序(Insertion Sort)是一种简单直观的排序算法,它的工作原理是将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增加1的有序表。它适用于少量数据的排序,或者当数据已经部分排序时,插入排序的效率会更高。

插入排序的基本步骤如下:

  1. 构建有序序列:从第一个元素开始,将其视为一个已经排序的序列。

  2. 选择待插入元素:取出下一个元素,在已经排序的序列中从后向前扫描。

  3. 插入元素:如果已排序序列中当前元素大于待插入元素,则将当前元素向右移动一位。

  4. 重复移动:继续将待插入元素与前一个元素比较,直到找到合适的插入点或移动到序列的开头。

  5. 放置元素:将待插入元素插入到找到的位置。

  6. 继续插入:对剩余的元素重复步骤2-5。

以下是代码实现:

#include <iostream>
using namespace std;
void Insertsort(int a[],int n)
{
    for(int i = 0; i < n; i++)
    {
   int x = a[i], j;//记录待插入元素
   for(j = i - 1; j >=0; j--)
   {
       if(x < a[j])//待插入元素小于前面的元素,则继续往前比
      a[j+1] = a[j];
          else    //待插入元素大于等于前面的元素,则停止比较
      break;
   }
   a[j+1] = x;//插入元素
    }
}
int main()
{
    int n, a[1000];
    cin >> n;
    for(int i = 0 ;i < n; i++)
    {
        cin >> a[i];
    }
    Insertsort(a,n);
    for(int i = 0 ;i < n; i++)
    {
        cout << a[i] << " ";
    }
    return 0;

插入排序的时间复杂度在最坏的情况下是O(n^2),如果输入数组已经或部分排序,则时间复杂度可以低至O(n)。空间复杂度是O(1),因为它只需要一个额外的存储空间来保存当前待插入的元素。这使得插入排序成为小规模数据集排序的理想选择。

5.接下来就是世界上最好用的快排!!!

sort函数 从小到大排序

#include<iostream>
#include<algorithm>
using namespace std;
int n, a[1000];
int main()
{
    cin >> n;
     for (int i = 0; i < n; i++)
     {
         cin >> a[i]; 
     } 
     sort(a, a + n);
     for (int i = 0; i < n; i++)
     {
         cout << a[i] << " "; 
     } 
     return 0;
}

sort从大到小排序

 

#include<iostream>
#include<algorithm>
using namespace std;
int n, a[1000];
bool cmp(int a, int b)
{
    return a > b;
}
int main()
{
     cin >> n;
     for (int i = 0; i < n; i++)
     {
         cin >> a[i]; 
     } 
     sort(a, a + n, cmp);
     for (int i = 0; i < n; i++)
     {
         cout << a[i] << " "; 
     } 
    return 0;
}

  • 21
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值