【C++】十大排序算法

文章目录

  • 十大排序算法
    • 插入排序O(n^2^)
    • 冒泡排序O(n^2^)
    • 选择排序O(n^2^)
    • 希尔排序——缩小增量排序O(nlogn)
    • 快速排序O(nlogn)
    • 堆排序O(nlogn)
    • 归并排序(nlogn)
    • 计数排序O(n+k)
    • 基数排序O(n*k)
    • 桶排序O(n+k)

十大排序算法

这里是引用

排序算法的稳定性:在具有多个相同关键字的记录中,若经过排序这些记录的次序保持不变,说排序算法是稳定的。

插入排序O(n2)

  • 直接插入排序

    动画演示如图:
    在这里插入图片描述

    代码如下:

void Straight_Insertion_Sort(int a[], int length)
{for (int i = 1; i < length; i++){if (a[i] < a[i - 1]){int temp = a[i];for (int j = i - 1; j >= 0; j--){a[j + 1] = a[j];if (a[j] < temp){a[j + 1] = temp;break;}if (j == 0 && a[j] > temp){a[j] = temp;}}}}
}
  • 折半插入排序

    主要分为查找和插入两个部分

    图片演示:

在这里插入图片描述

代码如下:

void Binary_Insert_Sort(int a[], int length)
{int low, high, mid;int i, j, temp;for (i = 1; i < length; i++){low  = 0;high = i - 1;temp = a[i];while (low <= high){mid = (low + high) / 2;if (temp < a[mid]){high = mid - 1;}else{low = mid + 1;}}   // whilefor (j = i - 1; j > high; j--){a[j + 1] = a[j];}a[j + 1] = temp;}   // for(i)
}

冒泡排序O(n2)

思路:两两比较元素,顺序不同就交换

图解:
在这里插入图片描述

代码:

void Bubble_Sort(int a[], int length)
{for (int i = 0; i < length - 1; i++){for (int j = 0; j < length - i - 1; j++){if (a[j] > a[j + 1]){int temp = a[j];a[j]     = a[j + 1];a[j + 1] = temp;}}}
}

选择排序O(n2)

思路:每一次从待排序的数据元素中选择最小(最大)的一个元素作为有序的元素。如果是升序排序,则每次选择最小值就行,这样已经排好序的部分都是生序排序选择排序是不稳定的,比如说(55231这种情况,两个5的相对顺序会变)

图解:
在这里插入图片描述
代码:

void Select_Sort(int a[], int length)
{for (int i = 0; i < length - 1; i++){int min_index = i;for (int j = i + 1; j < length; j++){if (a[min_index] > a[j]){min_index = j;}}   // for jif (i != min_index){int temp     = a[i];a[i]         = a[min_index];a[min_index] = temp;}}   // for i
}

希尔排序——缩小增量排序O(nlogn)

思路:

希尔排序又叫缩小增量排序,使得待排序列从局部有序随着增量的缩小编程全局有序。当增量为1的时候就是插入排序,增量的选择最好是531这样间隔着的。

其实这个跟选择排序一样的道理,都是不稳定的比如下图7变成9的话,就是不稳定的

图解:

在这里插入图片描述

代码:

void Shell_Sort1(int a[], int length)
{// 首先定义一个初始增量,一般就是数组长度除以2或者3int gap = length / 2;while (gap >= 1){for (int i = gap; i < length; i++){int temp = a[i];int j    = i;while (j >= gap && temp < a[j - gap]){a[j] = a[j - gap];j    = j - gap;}   // whilea[j] = temp;}   // forgap = gap / 2;}   // while
}
/*****************另一种写法, 好理解****************************/
void shellsort3(int a[], int n)
{int i, j, gap;for (gap = n / 2; gap > 0; gap /= 2)for (i = gap; i < n; i++)/*j>gap之后,j前面的可以重新比较依次保证j前面间隔gap的也是有序的*/for (j = i - gap; j >= 0 && a[j] > a[j + gap]; j -= gap)Swap(a[j], a[j + gap]);
}

快速排序O(nlogn)

思路:快排的核心叫做“基准值“,小于基准值的放在左边,大于基准值的放在右边。然后依次递归。基准值的选取随机的,一般选择数组的第一个或者数组的最后一个,然后又两个指针low和high

图解:“基准值就是第一个元素”

在这里插入图片描述

1)设置两个变量I、J,排序开始的时候:I=0,J=N-1;

2)以第一个数组元素作为关键数据,赋值给 key ,即 key =A[0];

3)从J开始向前搜索,即由后开始向前搜索(J=J-1即J–),找到第一个小于 key 的值A[j],A[j]与A[i]交换;

4)从I开始向后搜索,即由前开始向后搜索(I=I+1即I++),找到第一个大于 key 的A[i],A[i]与A[j]交换;

5)重复第3、4、5步,直到 I=J; (3,4步是在程序中没找到时候j=j-1,i=i+1,直至找到为止。找到并交换的时候i, j指针位置不变。另外当i=j这过程一定正好是i+或j-完成的最后另循环结束。)

代码:

// 快速排序 需要两个函数配合
int Quick_Sort_GetKey(int a[], int low, int high)
{int temp = a[low];while (low < high){// 首先比较队尾的元素和关键之temp,如果队尾大指针就往前移动while (low < high && a[high] >= temp){high--;}// 当a[high]<temp的时候,跳出循环然后将值付给a[low],a[low]=tempa[low] = a[high];// 赋值过一次之后就立刻从队首开始比较while (low < high && a[low] <= temp){low++;}a[high] = a[low];}                // while (low<high)a[low] = temp;   // 或者a[high]=tempreturn low;
}
void Quick_Sort(int a[], int low, int high)
{if (low < high){int key = Quick_Sort_GetKey(a, low, high);Quick_Sort(a, low, key - 1);Quick_Sort(a, key + 1, high);}
}

堆排序O(nlogn)

思路:堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。堆排序分为两步:首先将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。随后第二步将其与末尾元素进行交换,此时末尾就为最大值。然后将这个堆结构映射到数组中后,就会变成升序状态了。(即升序—大根堆)

当数组元素映射成为堆时:

  1. 父结点索引:(i-1)/2
  2. +左孩子索引:2**i*+1
  3. 左孩子索引:2**i*+2

图解:

在这里插入图片描述

基本思想:

  1. 首先将待排序的数组构造成一个大根堆,此时,整个数组的最大值就是堆结构的顶端
  2. 将顶端的数与末尾的数交换,此时,末尾的数为最大值,剩余待排序数组个数为n-1
  3. 将剩余的n-1个数再构造成大根堆,再将顶端数与n-1位置的数交换,如此反复执行,便能得到有序数组

代码:

// index是第一个非叶子节点的下标(根节点)
// 递归的方式构建
void Build_Heap(int a[], int length, int index)
{int left    = 2 * index + 1;   // index的左子节点int right   = 2 * index + 2;   // index的右子节点int maxNode = index;           // 默认当前节点是最大值,当前节点indexif (left < length && a[left] > a[maxNode]){maxNode = left;}if (right < length && a[right] > a[maxNode]){maxNode = right;}if (maxNode != index){int temp   = a[maxNode];a[maxNode] = a[index];a[index]   = temp;Build_Heap(a, length, maxNode);}
}
void Heap_Sort(int a[], int length)
{// 构建大根堆(从最后一个非叶子节点向上)// 注意,最后一个非叶子节点为(length / 2) - 1for (int i = (length / 2) - 1; i >= 0; i--){Build_Heap(a, length, i);}for (int i = length - 1; i >= 1; i--){// 交换刚建好的大顶堆的堆顶和堆末尾节点的元素值,int temp = a[i];a[i]     = a[0];a[0]     = temp;// 交换过得值不变,剩下的重新排序成大顶堆Build_Heap(a, i, 0);}
}

归并排序(nlogn)

思路:分治思想,将若干个已经排好序的子序合成有序的序列。

图解:

在这里插入图片描述

代码:

// 分治思想,先逐步分解成最小(递归)再合并
// 归并
void Merge(int a[], int low, int mid, int high)
{int  i    = low;int  j    = mid + 1;int  k    = 0;int* temp = new int[high - low + 1];while (i <= mid && j <= high){if (a[i] <= a[j]){temp[k++] = a[i++];}else{temp[k++] = a[j++];}}   // while (i<mid&&j<=high)while (i <= mid){temp[k++] = a[i++];}while (j <= high){temp[k++] = a[j++];}for (i = low, k = 0; i <= high; i++, k++){a[i] = temp[k];}delete[] temp;
}
// 递归分开
void Merge_Sort(int a[], int low, int high)
{if (low < high){int mid = (low + high) / 2;Merge_Sort(a, low, mid);Merge_Sort(a, mid + 1, high);cout << "mid=" << mid << " " << a[mid] << endl;cout << "low=" << low << " " << a[low] << endl;cout << "high=" << high << " " << a[high] << endl;cout << endl;// 递归之后再合并Merge(a, low, mid, high);}
}

代码看不懂没关系,参考链接

计数排序O(n+k)

思路:

将待排序的数据存放到额外开辟的空间中。首先找出元素的最大最小值,然后统计每个元素i出现的次数,然后放入数组i中,数组中存放的是值为i的元素出现的个数。额外数组中第i个元素是待排序数组中值为i的元素的个数。因为要求输入的数有确定范围,同时只能对整数进行排序,有场景限制。

图解:

计数排序

代码:

void Count_Sort(int a[], int length)
{// 得到待排序的最大值int max = a[0];int i   = 0;while (i < length - 1){max = (a[i] > a[i + 1]) ? a[i] : a[i + 1];i++;}int* countArray = new int[max + 1] { 0 };int* temp       = new int[length];for (int i = 0; i < length; i++){countArray[a[i]]++;}//!!!这一步的思想特别重要,在非比较排序中for (int i = 1; i < max + 1; i++){countArray[i] += countArray[i - 1];}// 反向遍历for (int i = length - 1; i >= 0; i--){temp[countArray[a[i]] - 1] = a[i];countArray[a[i]]--;}for (int i = 0; i < length; i++){a[i] = temp[i];}delete[] countArray;delete[] temp;
}

基数排序O(n*k)

思路: 基数也就表明桶的个数是定死的,就是10个。基数排序的思想是,从个位依次开始排序,首先按照个位的大小排序,将改变的序列按照十位开始排序,然后一次往后……

图解:

在这里插入图片描述

代码:

int Get_Max_Digits(int a[], int length)
{int max = a[0];int i   = 0;while (i < length - 1){max = (a[i] > a[i + 1]) ? a[i] : a[i + 1];i++;}int b = 0;   // 最大值的位数while (max > 0){max = max / 10;b++;}return b;
}
// 切记!桶子只能是十个,是定死的
void Radix_Sort(int b[], int length)
{int  d     = Get_Max_Digits(b, length);   // 得到最大值的位数int* temp  = new int[length];             // 开辟一个和原数组相同的临时数组// 根据最大值的位数进行排序次数循环int  radix = 1;for (int i = 0; i < d; i++){// 每次把数据装入桶子前先清空countint count[10] = { 0 };   // 计数器 每次循环都清零for (int j = 0; j < length; j++){// 统计尾数为0-9的个数,一次是个十百千....位int tail_number = (b[j] / radix) % 10;count[tail_number]++;   // 每个桶子里面的个数}// 桶中的每一个数的位置一次分配到temp数组中,先找到位置for (int j = 1; j < 10; j++){count[j] += count[j - 1];}// 分配到temp中排序后的位置for (int j = length - 1; j >= 0; j--){int tail_number              = (b[j] / radix) % 10;temp[count[tail_number] - 1] = b[j];count[tail_number]--;}// 赋值for (int j = 0; j < length; j++){b[j] = temp[j];}radix *= 10;}   // for(int i)delete[] temp;
}

桶排序O(n+k)

**思路:**基数排序和计数排序都是桶思想的应用。桶排序是最基本的

​ 首先要得到整个待排序数组的最大值和最小值,然后设置桶的个数k,这样可以得到每个桶可以放的数的区间。

​ 然后遍历待排序的数组,将相关区间内的数放到对应的桶中,这样桶内在排序,就使得整个序列相对有序

图解:

在这里插入图片描述

代码:

void bucketSort(int arr[], int len)
{// 确定最大值和最小值int max = INT_MIN;int min = INT_MAX;for (int i = 0; i < len; i++){if (arr[i] > max)max = arr[i];if (arr[i] < min)min = arr[i];}// 生成桶数组// 设置最小的值为索引0,每个桶间隔为1int bucketLen = max - min + 1;// 初始化桶int bucket[bucketLen];for (int i = 0; i < bucketLen; i++)bucket[i] = 0;// 放入桶中int index = 0;for (int i = 0; i < len; i++){index          = arr[i] - min;bucket[index] += 1;}// 替换原序列int start = 0;for (int i = 0; i < bucketLen; i++){for (int j = start; j < start + bucket[i]; j++){arr[j] = min + i;}start += bucket[i];}
}

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

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

相关文章

C++-UI入门

1、QWidget类 QWidget类时所有组件和窗口的基类。内部包含了一些最基础的界面特性。 常用属性&#xff1a; 1.1修改坐标 x : const int 横坐标&#xff0c;每个图形的左上角为定位点&#xff0c;横轴的零点在屏幕的最左边&#xff0c;正方向向右。 y : const int 纵坐标&#x…

Python——数据类型转换

# 将数字类型转换成字符串 num_str str(111) print(type(num_str), num_str) \# 将浮点类型转换成字符串 float_str str(12.34) print(type(float_str), float_str) # 将字符串转变成数字 num int("234") print(type(num)) # 将字符串转变成浮点型 num2 float(&q…

BitMap解析(一)

文章目录 前言数据结构添加与删除操作 JDK中BitSet源码解析重要成员属性初始化添加数据清除数据获取数据size和length方法集合操作&#xff1a;与、或、异或 前言 为什么称为bitmap&#xff1f; bitmap不仅仅存储介质以及数据结构不同于hashmap&#xff0c;存储的key和value也…

4D激光雷达

什么是4D激光雷达 4D激光雷达,也称为4D成像雷达,是一种利用回声定位和飞行时间测量概念来绘制三维环境中物体并附加速度信息的技术。相比于传统的3D激光雷达,4D激光雷达可以生成点云的3D坐标,并提供关于环境的第四维度信息,通常是速度。这种技术被广泛应用于自动驾驶汽车…

ML:2-2neural network layer

文章目录 1. 神经网络层2. 更复杂的神经网络3. 神经网络的前向传播 【吴恩达机器学习笔记p47-49】 1. 神经网络层 input&#xff1a;4个数字的向量。3个神经元分别做logistic regression。下角标&#xff1a;标识第 i 个神经元的值。上角标&#xff1a;表示第 j 层layer的值。…

打PTA 分数 15

传说这是集美大学的学生对话。本题要求你做一个简单的自动问答机&#xff0c;对任何一个问句&#xff0c;只要其中包含 PTA 就回答 Yes!&#xff0c;其他一概回答 No.。 输入格式&#xff1a; 输入第一行给出一个整型范围内的正整数 N&#xff0c;随后 N 行&#xff0c;每行给…

单片机原理及应用:中断系统结构与控制寄存器

大家好啊&#xff0c;这几天因为考试断更了一段时间&#xff0c;现在放假了也可以恢复正常的更新速度了。今天我们来认识一下单片机的中断系统&#xff0c;这里可以说是我们学习单片机以来第一个核心功能&#xff0c;我们会分几期内容来深入了解中断系统的作用原理和应用方式。…

vue+springboot+mybatis-plus实现乡村公共文化服务系统

项目前端&#xff1a;https://gitee.com/anxin-personal-project/rural-public-cultural-services-front 项目后端&#xff1a;https://gitee.com/anxin-personal-project/rural-public-cultural-services-behind 1.系统简介 乡村公共服务文化提供给管理员、商家、村民。管理…

36-javascript输出方式,弹框:普通,confirm弹框,prompt弹框,控制台输出:普通,warm,error

1.页面打印 <body><p>你真是一个小机灵鬼</p><script>// 页面打印document.write("打印内容");</script> </body> 2.覆盖文档 <body><p>你真是一个小机灵鬼</p><script>// 覆盖文档window.onload f…

用Java编写图书网站信息采集程序教程

目录 一、准备工作 二、分析目标网站结构 三、选择信息采集方式 四、安装Jsoup库 五、编写信息采集程序 六、注意事项 总结&#xff1a; 编写图书网站信息采集程序需要掌握HTML、CSS、JavaScript、Java等前端和后端技术。下面是一个简单的教程&#xff0c;介绍如何使用…

1880_安装QEMU_for_ARC

Grey 全部学习内容汇总&#xff1a; https://github.com/GreyZhang/g_ARC 主标题 想学习一点ARC相关的知识&#xff0c;但是手里没有开发板。看了下&#xff0c;使用QEMU似乎是一个很好的选择&#xff0c;正好也有这么一个分支。在此&#xff0c;记录一下环境搭建的过程。 …

一文快速学会Docker软件部署

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;首期文章 &#x1f4da;订阅专栏&#xff1a;Docker 希望文章对你们有所帮助 做项目的时候&#xff0c;感觉很多地方的配置都特别…

扫码能看图片吗?图片怎么弄成二维码?

在外出游玩或者参加展览时&#xff0c;经常会看到很多的物品或者展物都会有一个对应的二维码&#xff0c;通过扫码就可以查看详情&#xff0c;其中很多的内容为了美观性都会单独将内容设计成图片存入二维码中&#xff0c;那么图片制作二维码怎么制作呢&#xff1f; 想要快速的…

数模学习day10-聚类模型

说明&#xff0c;本文部分图片和内容源于数学建模交流公众号 目录 K-means聚类算法 K-means聚类的算法流程&#xff1a; 图解 算法流程图 评价 K-means算法 基本原则 算法过程 Spss软件操作 K-means算法的疑惑 系统&#xff08;层次&#xff09;聚类 算法流程 Sp…

安卓逆向某脚本-autojs逆向

引言 上次讲到,为了静态分析,逆向了所有加密字符串。来看下今天我们看下他的流程。 分析app 启动之后会出现一个更新按钮,如图:我们先看下一般autojs 项目是怎么打包的,打包的时候可以选择加密类型,选择dex 类型,然后就是把js 文件变成dex 。 我们先看下一般autojs 项目是…

【python】TCP测速程序

一、服务端 下面是一个简单的 Python 服务端程序的示例&#xff0c;使用标准库中的 socket 模块来建立一个 TCP 服务器。该服务器接收客户端的连接请求&#xff0c;客户端发送一定大小的数据流以测试 TCP 带宽。 实际场景中带宽测试可能需要更复杂的逻辑来确保测试的准确性。 …

万能字符单词拼写 - 华为OD统一考试

OD统一考试(C卷) 分值: 100分 题解: Java / Python / C++ 题目描述 有一个字符串数组 words 和一个字符串 chars。假如可以用 chars 中的字母拼写出 words 中的某个"单词"(字符串),那么我们就认为你掌握了这个单词。 words 的字符仅由 a-z 英文小写宁母组成,…

浅析内存一致性:内存屏障

文章目录 概述内存乱序访问Store Buffer和Invalidate QueueStore BufferStore ForwardingStore Buffer与内存屏障 Invalidate QueueInvalidate Queue与内存屏障 内存屏障分类编译器屏障CPU内存屏障 相关参考 概述 内存屏障&#xff0c;是一类同步屏障指令&#xff0c;是CPU或编…

分布式锁3: zk实现分布式锁2 使用临时节点(需要自旋)

一 使用临时节点实现分布式锁 1.1 代码截图 1.2 代码如下 由于zookeeper获取链接是一个耗时过程&#xff0c;这里可以在项目启动时&#xff0c;初始化链接&#xff0c;并且只初始化一次。借助于spring特性&#xff0c;代码实现如下&#xff1a; package com.atguigu.distri…

Spring MVC MVC介绍和入门案例

1.SpringMVC概述 1.1.MVC介绍 MVC是一种设计模式&#xff0c;将软件按照模型、视图、控制器来划分&#xff1a; M&#xff1a;Model&#xff0c;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据 JavaBean分为两类&#xff1a; 一类称为数据承载Bean&#xf…