【数据结构】冒泡,快速,直接插入,归并,选择排序

news2024/11/22 15:18:30

🎊专栏【数据结构】

🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。

🎆音乐分享【Dream It Possible】

大一同学小吉,欢迎并且感谢大家指出我的问题🥰

目录

🎁冒泡排序

🏳️‍🌈图解

🏳️‍🌈实现过程

🏳️‍🌈代码

🎁快速排序

🏳️‍🌈图解

🏳️‍🌈实现过程

🏳️‍🌈代码

🎁直接插入排序

🏳️‍🌈图解

🏳️‍🌈实现过程

🏳️‍🌈代码 

🎁归并排序

🏳️‍🌈图解

 🏳️‍🌈实现过程

🏳️‍🌈代码

🎁选择排序

🏳️‍🌈图解

🏳️‍🌈实现过程

🏳️‍🌈代码


🎁冒泡排序

冒泡排序是一种简单的排序算法,它重复遍历需要排序的数列,每次遍历时比较相邻两个元素的大小,并将它们按照升序或降序的方式进行交换,直到整个数列都排序完成为止。

🏳️‍🌈图解

 

🏳️‍🌈实现过程

  1. 从数列的第一个元素开始,对相邻的两个元素进行比较;
  2. 如果当前元素比后面的元素大(或小,根据排序顺序而定),则交换它们的位置;
  3. 继续向后遍历,知道全部元素都被遍历完成;
  4. 重新开始新一轮的遍历操作,但是此时最后一个元素已经不需要再进行比较和交换了,因为已经是最大(或最小)值;
  5. 重复以上步骤,直到整个数列都被排序完成。

由于每次遍历只能确保一个元素被排序到了正确的位置,因此需要执行多轮的遍历操作才能够保证整个数列都被排序。冒泡排序的时间复杂度为 O(n^2),虽然效率不高,但是实现简单易懂,适用于对较小数列进行排序。

🏳️‍🌈代码

#include <iostream>
using namespace std;

void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = 0; j < n - i - 1; j++) {   
            if (arr[j] > arr[j + 1]) {
                // 交换相邻两个元素的值
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

int main() {
    int arr[] = {5, 2, 6, 3, 1, 4};
    int n = sizeof(arr) / sizeof(arr[0]);
    bubbleSort(arr, n);
    cout << "排序后的结果为: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

🎁快速排序

快速排序是一种基于“分治法”的排序算法,由C. A. R. Hoare在1960年提出。它通常被认为是最快的通用排序算法之一,并且也是很多编程语言库中的默认排序算法之一。

快速排序的基本思想是:选择一个基准元素(pivot),将待排序的序列分割成两个子序列,其中一个子序列中的所有元素都比基准元素小,另一个子序列中的所有元素都比基准元素大,然后对这两个子序列进行递归排序,直到整个序列有序。

🏳️‍🌈图解

 

🏳️‍🌈实现过程

具体实现过程如下:

  1. 从数列中选择一个基准元素;
  2. 将数列中的所有元素分成两个子序列,其中一个子序列中的所有元素都比基准元素小,另一个子序列中的所有元素都比基准元素大;
  3. 对这两个子序列分别执行递归排序操作,直到整个序列有序。

快速排序的时间复杂度取决于基准元素的选择,最坏情况下的时间复杂度为 O(n^2),但通常情况下时间复杂度为 O(nlogn),并且需要额外的空间来存储递归调用栈。

🏳️‍🌈代码

#include<iostream>
using namespace std;
int a[100010];
int n;
void quickSort(int a[], int l, int r){
    //如果数组中就一个数,就已经排好了,直接返回。
    if(l >= r) return;
    //选取分界线。这里选数组中间那个数
    int x = a[l + r >> 1];
    int i = l - 1, j = r + 1;
    //划分成左右两个部分
    while(i < j){
        while(a[++i] < x);
        while(a[--j] > x);
        if(i < j){
            swap(a[i], a[j]);
        }
    }
    //对左部分排序
    quickSort(a, l, j);
    //对右部分排序
    quickSort(a, j + 1, r);
}

int main(){
    cin >> n;
    for(int i = 0; i < n; i++){
        cin >> a[i];
    }
    quickSort(a, 0, n - 1);
    for(int i = 0; i < n; i++){
        cout << a[i] << " ";
    }
}

🎁直接插入排序

直接插入排序是一种简单的、稳定的排序算法,它的基本思想是将一个待排序的数列看作是由一个有序序列和一个无序序列组成。每次从无序序列中选择一个元素,将其插入到有序序列的适当位置中,从而保证插入后的序列仍然有序。

🏳️‍🌈图解

🏳️‍🌈实现过程

  1. 将第一个元素看作是一个有序序列;
  2. 依次将无序序列中的元素插入到有序序列的适当位置中,直到整个序列有序为止;

插入过程中,为了将一个元素插入到有序序列的适当位置中,需要先在有序序列中查找到该元素所应该插入的位置(即需要比较待插入元素与有序序列中已有元素的大小),然后将该元素插入到该位置上,并调整有序序列中的其他元素的位置。插入过程中,需要将待插入元素往后移动,腾出插入位置。

直接插入排序的时间复杂度为 O(n^2),在最坏情况下需要进行 n-1 次比较和移动,但在实际应用中,由于它的操作次数与待排序序列的初始状态有关,因此在部分相对有序的序列中表现良好。

🏳️‍🌈代码 

#include <iostream>
using namespace std;

// 直接插入排序函数
void insertSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        int j = i - 1;
        int key = arr[i];
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j--;
        }
        arr[j + 1] = key;
    }
}

int main() {
    int arr[] = {5, 2, 6, 3, 1, 4};
    int n = sizeof(arr) / sizeof(arr[0]);
    insertSort(arr, n);
    cout << "排序后的结果为: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

🎁归并排序

归并排序是一种采用分治策略的排序算法,其基本思想是将一个待排序的数列不断地二分,直到这些子序列都只剩下一个元素。然后再将相邻的子序列两两合并,形成新的有序序列,如此往复,直到最后只剩下一个有序序列为止。

🏳️‍🌈图解

 🏳️‍🌈实现过程

归并排序的具体实现如下:

  1. 将待排序的数列不断地二分,直到每个子序列只包含一个元素;
  2. 将相邻的两个有序子序列合并成一个有序序列;
  3. 重复第二步操作,直到最后只剩下一个有序序列为止;

在实现中,需要实现一个 merge 函数,用于将两个有序数组合并成一个有序数组。具体操作过程如下:

  1. 创建一个临时数组 temp,长度等于两个有序数组的长度之和;
  2. 依次比较两个有序数组中的元素,将较小的元素放入 temp 数组中,直到其中一个数组中的所有元素都被放入为止;
  3. 将另一个数组中的所有剩余元素依次放入 temp 数组中;
  4. 将 temp 数组中的元素复制回原数组中。

归并排序的时间复杂度为 O(nlogn),它的性能稳定,并且在处理大规模数据时表现较优。但是它的空间复杂度较高,需要额外的存储空间。

🏳️‍🌈代码

#include <iostream>
using namespace std;

// 合并两个有序数组
void merge(int arr[], int l, int mid, int r) {
    int n1 = mid - l + 1;
    int n2 = r - mid;
    int L[n1], R[n2];
    for (int i = 0; i < n1; i++) {
        L[i] = arr[l + i];
    }
    for (int j = 0; j < n2; j++) {
        R[j] = arr[mid + 1 + j];
    }
    int i = 0, j = 0, k = l;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        } else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }
}

// 归并排序函数
void mergeSort(int arr[], int l, int r) {
    if (l < r) {
        int mid = l + (r - l) / 2;
        mergeSort(arr, l, mid);
        mergeSort(arr, mid + 1, r);
        merge(arr, l, mid, r);
    }
}

int main() {
    int arr[] = {5, 2, 6, 3, 1, 4};
    int n = sizeof(arr) / sizeof(arr[0]);
    mergeSort(arr, 0, n - 1);
    cout << "排序后的结果为: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

🎁选择排序

选择排序是一种简单直观的排序算法,它的基本思想是,每次从待排序的序列中选择一个最小(或最大)的元素,将其放置在已排好序的序列的末尾,直到所有元素都被排序完毕为止。

🏳️‍🌈图解

 

🏳️‍🌈实现过程

具体实现过程如下:

  1. 在待排序序列中找到最小元素,并将其放置在序列的起始位置;
  2. 在剩余未排序的序列中继续寻找最小元素,并将其放置在已排序序列的末尾;
  3. 重复第二步操作,直到所有元素都被排序完毕。

选择排序的时间复杂度为 O(n^2),且由于其每次只能确定一个元素的位置,因此其性能不够稳定。但是由于其实现简单,空间复杂度低,因此在少量数据的情况下,选择排序仍然具有一定优势。

🏳️‍🌈代码

#include <iostream>
using namespace std;

void selectionSort(int arr[], int n) {
    int minIndex, temp;
    for (int i = 0; i < n - 1; i++) {
        minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
}

int main() {
    int arr[] = {5, 2, 6, 3, 1, 4};
    int n = sizeof(arr) / sizeof(arr[0]);
    selectionSort(arr, n);
    cout << "排序后的结果为: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

🥰如果大家有不明白的地方,或者文章有问题,欢迎大家在评论区讨论,指正🥰   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/575559.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CentOS7.4安装OpenVPN

系统环境 [rootvpn ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) 一. 准备工作 [rootvpn ~]# yum -y install openssl-devel openssl pam pam-devel lzo lzo-devel pkcs11-helper pkcs11-helper-devel 二. 安装OpenVPN服务 1. 下载openvpn源码包 [r…

【计算机网络 - 第六章】链路层

目录 一、概述 1、数据链路层提供的服务&#xff1f; 二、差错检测 1、奇偶校验 2、循环冗余校验CRC 三、多路访问链路和协议 1、概述 &#xff08;1&#xff09;多路访问协议 2、信道划分协议 ① 频分多路复用FDM ② 时分多路复用TDM ③ 波分多路复用WDM ④ 码分…

更好看的国产蓝牙耳机,音质也没问题,哈氪零度青春版体验

夏天躲在空调房里戴着耳机听音乐、玩游戏是很多人的日常&#xff0c;这两年国产耳机做得越来越好了&#xff0c;设计也很有新意&#xff0c;像是我现在用的这款哈氪零度青春版&#xff0c;就采用了一种冰封造型设计&#xff0c;视觉效果很新颖&#xff0c;看起来很有立体感&…

【一个简单的前后端交互页面】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 客户端与服务器之间的通信流程 理解当前案例…

chatgpt赋能python:Python文件拆分技巧详解

Python 文件拆分技巧详解 随着数据量的不断增大&#xff0c;我们经常需要处理非常大的数据文件&#xff0c;这时候就需要用到文件拆分技巧。在Python中&#xff0c;文件拆分可以帮助我们提高数据处理的效率&#xff0c;这是一个非常实用的技巧。在本篇文章中&#xff0c;我们将…

奇巴布Feed流性能优化

01 项目背景 “爱奇艺奇巴布”是爱奇艺为0-8岁孩子和家长定制化设计的寓教于乐平台&#xff0c;为儿童量身打造精致的观看体验&#xff0c;精彩内容解锁寓教于乐新方式。为儿童提供优质动画内容的同时&#xff0c;我们更关注APP用户体验。在产品交互设计上我们立足儿童视角&…

抖音SEO矩阵系统开发分享及搭建流程

目录 产品功能亮点 产品介绍及开发背景 开发要求及实现流程 产品功能亮点 1. 支持多账号多平台一键 授权管理 2.支持矩阵视频批量剪辑&#xff0c;批量发布 3. 多平台关键词布局&#xff0c;提升企业及产品曝光 4. 评论区关键词自动回复&#xff0c;意向线索智能挖掘 5…

RTOS专栏(一) —— rt-thread简单介绍和qemu使用

本期主题&#xff1a; 简单介绍rt-thread介绍qemu和rt-thread怎么配合使用qemu的简单例子 rt-thread & qemu 1.rt-thread介绍2.qemu介绍3.搭建rt-thread和qemu开发环境4.简单例子 1.rt-thread介绍 RT-Thread 是一款完全由国内团队开发维护的嵌入式实时操作系统&#xff0…

《操作系统》期末主观题梳理

操作系统简答题 文章目录 操作系统简答题第一章第二章第三章第四章第五章第六章第七章第八章第九章 第一章 在计算机系统上配置OS(operating system, 操作系统)的目标是什么?作用主要表现在哪几个方面? 在计算机系统上配置OS, 主要目标是实现&#xff1a;方便性、有效性、可…

Error: Flash Download failed - Target DLL has been cancelled

文章目录 背景参考 背景 在使用keilv5进行STM32开发时&#xff0c;配置用JLink进行文件烧录&#xff0c;出现如下错误&#xff1a; 查阅资料&#xff0c;是因为Keil未识别烧录工具&#xff0c;需要进行下面的操作&#xff1a; 1.打开工程配置窗口&#xff0c;点开Debug选项卡…

并查集专题

⭐️前言⭐️ 本篇文章主要介绍与并查集相关的题目。 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持续更新学习记录收获&#xff0c;友友们有任何问题可以在评论区留言 &#x1f349;博客中涉及源码及博主…

阿里「通义千问」内测详细使用体验

名人说&#xff1a;一花独放不是春&#xff0c;百花齐放花满园。——《增广贤文》 作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、简要介绍二、分类问题测试0️⃣自我介绍1️⃣生成内容2️⃣回答问题3️⃣对话协…

springboot+vue大学生租房系统(java项目源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的大学生租房系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 &#x1f495;&#x1f495;作者&#xff1a;风歌…

太稳了,支付系统就该这么设计

支付中心系统对内为各个业务线提供统一的支付、退款等服务&#xff0c;对外对接三方支付或银行服务实现资金的流转。如下图&#xff1a; 大部分公司基本都是这样的架构&#xff0c;主要有以下几方面的优点&#xff1a; 形成统一支付服务&#xff0c;降低业务线接入成本及重复研…

数据结构-树,森连,二叉树之间的转换

树》二叉树 1.给兄弟加线 2.给出长子外的孩子去线 3.层次调整 &#xff08;整体向左偏移45&#xff09; eg&#xff1a; 1.给兄弟加线&#xff1a; 2.给处长紫外的孩子去线 3.层次调整&#xff0c;整体向左偏移45 &#xff08;由兄弟转化来的孩子都是右节点&#xff0c…

DJ6-5 目录管理

目录 6.5.1 文件控制块和索引结点 1、文件控制块 FCB 2、索引节点 6.5.2 简单文件目录 1、单级目录结构 2、二级目录结构 3、树形目录结构 6.5.3 目录查询技术 1、线性检索法 2、Hash 方法 文件目录&#xff1a;是指由文件说明索引组成的用于文件检索的特殊文件…

chatgpt赋能python:Python文件复制到指定文件夹——实现简单又高效的文件操作

Python 文件复制到指定文件夹——实现简单又高效的文件操作 如今&#xff0c;人们对于数据的需求越来越多&#xff0c;因此在编程过程中&#xff0c;对于文件的操作也变得越来越重要。而Python作为一种高效而简洁的编程语言&#xff0c;其文件操作也是十分出色的。本文将会带领…

C/C++ ---- 内存管理

目录 C/C内存分布 常见区域介绍 经典习题&#xff08;读代码回答问题&#xff09; 选择题 填空题 C语言内存管理方式 malloc/free calloc realloc C内存管理方式 new和delete操作内置类型 new和delete操作自定义类型 operator new和operator delete函数 new和dele…

Linux环境变量总结

Linux是一个多用户的操作系统。多用户意味着每个用户登录系统后&#xff0c;都有自己专用的运行环境。而这个环境是由一组变量所定义,这组变量被称为环境变量。用户可以对自己的环境变量进行修改以达到对环境的要求。 设置环境变量的方法 对所有用户生效的永久性变量 这类变…

K8s进阶6——pod安全上下文、Linux Capabilities、OPA Gatekeeper、gvisor

文章目录 一、Pod安全上下文1.1 配置参数1.2 案例11.2.1 dockerfile方式1.2.2 pod安全上下文方式 1.3 案例21.4 Linux Capabilities方案案例1案例2 二、pod安全策略2.1 PSP&#xff08;已废弃&#xff09;2.1.1 安全策略限制维度 2.2 OPA Gatekeeper方案2.2.1 安装Gatekeeper2.…