C++数据结构算法(二)排序算法集合(一)

简介: C++数据结构算法(二)排序算法集合(一)

排序算法(Sorting Algorithm) 的作用在于对于给定的一个元素序列,输出满足某种顺序的该序列的一个排列。


image.png

代码实现 —— 数最小值


数组最小值


首先,如何找到n个元素的最小值,并记录它的位置?


最开始,我们默认最小值出现在数组的第1位,所以,用于记录最小值位置的变量min_pos初始值为1。


然后,枚举数组中的每个元素,并且将当前记录的最小值和枚举到的第i个元素作比较,如果当前枚举到的元素更小,说明最小值不可能出现在原来的min_pos位置,而更有可能出现的位置i。所以,将min_pos更新为i。


当扫描完整个元素后,min_pos中的位置就是最小值出现的位置。

#include <bits/stdc++.h>
using namespace std;
int a[1010];
int n;
int main() {
    // 输入
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i]; 
    //注意:为保持认知一致,我们直接从数组第2个元素开始。数组第二个元素索引为1,不是从索引为0的元素开始哦。
    int min_pos = 1;    // 设置最小值位置的初始值为0,即a[1] = 0
    for (int i = 2; i <= n; ++i) {
        if (a[i] < a[min_pos])  // 比较当前枚举到的元素与当前记录位置的元素
            min_pos = i;        // 如果当前记录位置的元素更小,则更新最小值出现的位置
    }
    cout << "minimum value = " << a[min_pos] << endl;    // 输出最小值
    cout << "minimum value pos = " << min_pos << endl;   // 输出最小值的位置
    return 0;
}
int main() {
    int min_pos = 1;    // 设置最小值位置的初始值为0,即a[1] = 0
    for (int i = 2; i <= n; ++i) {
    // TODO 请补全代码找到最小值
        if(a[i]<a[min_pos])  // 比较当前枚举到的元素与当前记录位置的元素
           min_pos = i;  // 如果当前记录位置的元素更小,则更新最小值出现的位置
    }
    cout << "minimum value = " << a[min_pos] << endl;    // 输出最小值
    cout << "minimum value pos = " << min_pos << endl;   // 输出最小值的位置
    return 0;
}

代码实现 —— 实现选择排序


实现选择排序


所以,给定长度为n的序列,我们现在用之前描述的选择排序过程用C++语言实现出来,将序列从小到大排序。


最外层用for循环枚举当前应该归位的第i个元素;


内层用上一步方法的寻找最小值位置,找出第i位一直到第n位的最小值,并且将其与原来的第i位元素交换。


具体实现代码如下:

#include <bits/stdc++.h>
using namespace std;
int a[1010];
int n;
int main() {
    // 输入
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    // 选择排序过程
    for (int i = 1; i < n; ++i) {  // 枚举应该归位的第i个元素,这里因为前n-1位归为以后,
                                   // 第n位也会归位,所以我们只枚举到n-1。
        int min_pos = i;           // 将最小值位置设置为当前范围i~n的首位
        for (int j = i + 1; j <= n; ++j) { // 将第i个元素和剩下的元素相比较
            if (a[j] < a[min_pos]) {       // 如果当前元素小于之前维护的最小值
                min_pos = j;               // 更改最小值出现的位置
            }
        }
        swap(a[i], a[min_pos]);            // 将最小值与第i个位置交换
    }
    // 输出
    for (int i = 1; i <= n; ++i) 
        cout << a[i] << ' ';
    return 0;
}


总结


选择排序的基本思路是:


按照1~n的顺序,将每个元素依次归位。


当归位第i个元素时,我们需要选择出第i个元素到第n个元素的最小值,并且与第i个位置的元素交换。此时,1~i的元素分别为第1小到第i小的元素。


当第n个元素归位完毕以后,整个序列的排序过程结束。


冒泡排序:

基本思想


试想一下,如果在上体育课的时候,通常学生都会随意站成一列,但是体育老师会帮忙调整学生的站位使得最终顺序是按照身高排序的。那么,回忆一下体育老师是如何调整顺序的呢?


假设体育老师想将学生从左到右按照身高从矮到高排序。通常情况下,他会从左到右扫视学生的身高。如果左边有一个同学,个子比右边的同学高,他就要将其进行调整。具体调整方法是:


如果一个同学比他右边的同学高,就让这两个同学交换位置。

如果交换过后,这个同学仍然比新的右边的同学高,那么继续交换,直到他不在比右边的同学高。

这样进行了若干次以后,队列就按照身高排好序了。


image.png

我们发现,这里我们使用了将原问题转换为规模更小的子问题的思路。


所以在选择排序的过程,相当于每次将当前序列未排序部分的最小元素归位,将未排序的序列长度缩小一位。同样,如果我们能够通过某种方式,把序列中的最大值移动到序列最后面,也可以起到将未排序序列长度缩小一位的效果。

image.png


所以,这节课我们设计的排序过程分为两步:


通过“体育老师交换方法”,使得每次我们都能把最大值移动到序列的最后一位。

利用上面的步骤进行问题转换,将未排序的序列长度缩减一个。

这就是冒泡排序的具体思路,而上面提到的“将最大值移动到最后一位”的操作,就叫做冒泡操作。


冒泡排序的思路


总结冒泡排序的思路:

冒泡排序分为n-1个阶段。

在第1个阶段,通过“冒泡”,将前n个元素的最大值移动到序列的最后一位。此时只剩前n-1个元素未排序。

在第i个阶段,此时序列前n-i+1个元素未排序。通过“冒泡”,我们将前n-i+1个元素中的最大值移动到最后一位。此时只剩前n-i个元素未排好序。

最终到第n-1个阶段,前2个元素未排序。将其中的较大值移动到后一位,则整个序列排序完毕。

单独冒泡:

if (a[i] > a[i + 1]) swap(a[i], a[i + 1]);

单独的冒泡过程:

#include <bits/stdc++.h>
#define N 1010
using namespace std;
int n, a[N];
int main() {
    // 输入
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    // 冒泡阶段:连续交换过程
    for (int i = 1; i < n; ++i)    // 枚举两两交换的前一个元素序号
        if (a[i] > a[i + 1]) swap(a[i], a[i + 1]);    // 如果前一个元素大于后一个,就进行交换
    // 输出
    for (int i = 1; i <= n; ++i) cout << a[i] << ' ';
    cout << endl;
    return 0;
}


完整的冒泡过程:

#include <bits/stdc++.h>
#define N 1010
using namespace std;
int n, a[N];
int main() {
    // 输入
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    // 冒泡排序
    for (int i = 1; i < n; ++i) {  // 一共n-1个阶段,在第i个阶段,未排序序列长度从n-i+1到n-i。
        for (int j = 1; j <= n - i; ++j)  // 将序列从1到n-i+1的最大值,移到n-i+1的位置
            if (a[j] > a[j + 1])    // 其中j枚举的是前后交换元素的前一个元素序号
                swap(a[j], a[j + 1]);
    }
    // 输出
    for (int i = 1; i <= n; ++i) cout << a[i] << ' ';
    cout << endl;
    return 0;
}

复杂度分析


从代码中,我们可以看到冒泡排序的主干部分有两层循环,并且每一层的循环次数都在O(n)O(n)左右的数量级。


所以完整的冒泡排序时间复杂度是O(n^2)O(n2)。


总结


冒泡排序和选择排序一样,都是将原问题转换为长度减一的子问题的过程。


冒泡排序分为n-1个阶段,每个阶段通过“冒泡”的过程,将未排序序列中的最大值移动到最后一位。


冒泡的过程,具体是通过一段连续交换过程使得最大元素被“传送”到最后一位。


练习4·代码题


明明的随机数_冒泡排序


明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作。


输入描述:


每组输入有2行,第1行为1个正整数,表示所生成的随机数的个数N,第2行有N个用空格隔开的正整数,为所产生的随机数。


输出描述:


每组输出也是2行,第1行为1个正整数M,表示不相同的随机数的个数。第2行为M个用空格隔开的正整数,为从小到大排好序的不相同的随机数。


示例 1:


输入:

10
20 40 32 67 40 20 89 300 400 15

输出:

8
15 20 32 40 67 89 300 400


代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 110
using namespace std;
int a[N], n, cnt;
int main() {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
    // TODO 请补全下述代码,使用冒泡排序完成排序
    for (int i=1; i<n; i++){
        for (int j=0; j<n-i; j++){
            if (a[j]>a[j+1]) swap(a[j] , a[j+1]);
        }
    }
    cnt = 0;
    for (int i = 0; i < n; ++i) 
        if (i == 0 || a[i] != a[i - 1]) 
            a[cnt++] = a[i];
    printf("%d\n", cnt);
    for (int i = 0; i < cnt; ++i) printf("%d ", a[i]); 
    return 0;
}


目录
打赏
0
0
0
0
88
分享
相关文章
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
45 15
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
23天前
|
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
47 9
 算法系列之数据结构-二叉树
|
21天前
|
算法系列之数据结构-Huffman树
Huffman树(哈夫曼树)又称最优二叉树,是一种带权路径长度最短的二叉树,常用于信息传输、数据压缩等方面。它的构造基于字符出现的频率,通过将频率较低的字符组合在一起,最终形成一棵树。在Huffman树中,每个叶节点代表一个字符,而每个字符的编码则是从根节点到叶节点的路径所对应的二进制序列。
40 3
 算法系列之数据结构-Huffman树
算法系列之排序算法-堆排序
堆排序(Heap Sort)是一种基于堆数据结构的比较排序算法。它的时间复杂度为 $O(nlogn)$,并且是一种原地排序算法(即不需要额外的存储空间)。堆排序的核心思想是利用堆的性质来维护一个最大堆或最小堆,然后逐步将堆顶元素(最大值或最小值)取出,放到数组的末尾,最终得到一个有序的数组。
34 8
算法系列之排序算法-堆排序
|
22天前
|
算法系列之数据结构-二叉搜索树
二叉查找树(Binary Search Tree,简称BST)是一种常用的数据结构,它能够高效地进行查找、插入和删除操作。二叉查找树的特点是,对于树中的每个节点,其左子树中的所有节点都小于该节点,而右子树中的所有节点都大于该节点。
63 22
JavaScript 中通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能,JS中排序算法的使用详解(附实际应用代码)
Array.sort() 是一个功能强大的方法,通过自定义的比较函数,可以处理各种复杂的排序逻辑。无论是简单的数字排序,还是多字段、嵌套对象、分组排序等高级应用,Array.sort() 都能胜任。同时,通过性能优化技巧(如映射排序)和结合其他数组方法(如 reduce),Array.sort() 可以用来实现高效的数据处理逻辑。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
97 29
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
26 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等