C++实现——排序算法总结

2023-11-11

这里写图片描述

/*
常见的排序算法有:直接插入 希尔  冒泡 快速  选择 堆排序 归并  基数
*/

这里写图片描述

//下面一一分析,并实现:
/*
1.冒泡排序
 冒泡排序是最简单的排序算法,冒泡排序的基本思想是从后往前(或从前往后)两两比较相邻元素的值,若为逆序,则交换它们,直到序列比较完毕。我
 们称它为一趟冒泡。每一趟冒泡都会将一个元素放置到最终的位置上。
*/
//从前往后遍历,保证排好序的放到右侧
void BubbleSort_from_0(vector<int>& nums){
    int n = nums.size();
    //一共进行n-1趟
    for (int i = 0; i < n - 1; i++){
        //注意j的起点和终点
        for (int j = 1; j < n - i; j++){
            if (nums[j] < nums[j - 1]){
                swap(nums[j], nums[j - 1]);
            }
        }
    }
}

//从后往前遍历,保证排好序的放到左侧
void BubbleSort_from_n(vector<int>& nums){

    int n = nums.size();
    //一共进行n-1趟
    for (int i = 0; i < n - 1; i++){
        //注意j的起点和终点
        for (int j = n-1; j >i; j--){
            if (nums[j] < nums[j-1]){
                swap(nums[j], nums[j - 1]);
            }

        }

    }

}

/*
2.快速排序
快速排序是对冒泡排序的一种改进。其基本思想是基于分治法:在待排序表L[n]中任取一个元素
pivot作为基准,通过一趟排序将序列划分为两部分L[1…K-1] 和L[K+1…n],使得L[1…
K-1]中的所有元素都小于pivot,而L[k+1…n]中的所有元素都大于或等于pivot。则pivot放
在了其最终的位置L(k)上。然后,分别递归对两个子序列重复上述过程,直至每部分内只有一个元
素或空为止,即所有元素放在了其最终的位置上。
这里写图片描述

需要注意的是:关于遍历可以从两头开始,也可以只从一侧开始,下边都会给出实现
*/

int Partion_from_LR(vector<int>&nums, int left, int right){
    //取左元素作为哨兵
    int key = nums[left];
    while (left < right){
        //一开始认为左侧位置是空的,所以从右侧找一个数来填充它
        while (left < right && nums[right] >= key)--right;
        nums[left] = nums[right];
        //轮到从左侧找一个合适的数来填充右侧right的空缺
        while (left < right&& nums[left] < key)++left;
        nums[right] = nums[left];
    }
    //最后把中间的空缺位置放上key
    nums[left] = key;
    //返回最终位置
    return left;

}

int Partion_from_L(vector<int>&nums, int left, int right){
    //从一侧开始的一般取另一侧的端点为key.因此取右侧端点为key
    int key = nums[right];
    //设置两个指针 i ,left
    int i = left - 1;
    while (left <=right){
        //保证i~left(不包含i)之间的数都比key大,0~i(含i)的数比key小
        if (nums[left] <= key){
            ++i;
            swap(nums[left], nums[i]);
        }
        ++left;
    }
    return i;
}

void QuickSort(vector<int> &nums, int left, int right){
    //递归法
    if (left < right){
        //int pos = Partion_from_L(nums, left, right);
        int pos = Partion_from_LR(nums, left, right);
        QuickSort(nums, left, pos - 1);
        QuickSort(nums, pos + 1, right);
    }
}

/*
3.简单选择排序
对要排序的序列,选出关键字最小的数据,将它和第一个位置的数据交换,接着,选出关键字次小的
数据,将它与第二个位置上的数据交换。以此类推,直到完成整个过程
所以如果有n个数据,那么则需要遍历n-1遍。
实现代码如下:
*/

//选择排序
void SelectSort(vector<int> &nums){
    int n = nums.size();
    //只需n-1个位置需要考察,因为最后一个自然而然就放上了
    for (int i = 0; i < n - 1; i++){
        //每一趟我都是要去找最小的那个的序号
        int minx = nums[i];
        int cur = i;
        for (int j = i+1; j < n; j++){
            if (minx > nums[j]){
                cur = j;
            }
        }
        //交换
        swap(nums[cur], nums[i]);
    }
}

/*
4.直接插入排序
为了实现N个数的排序,将后面N-1个数依次插入到前面已经排好的子序列中,假定刚开始第一个
数是一个已拍好序的子序列,那么经过N-1趟就能得到一个有序的序列。
代码实现如下:
*/

//插入排序
void InsertSort(vector<int>& nums){
    //少于两个元素的数组不用排序
    if (nums.size() < 2)return;

    //排序从第二个元素进行考察
    int n = nums.size();
    for (int i = 1; i < n; i++){
        int key = nums[i];
        int j;
        for ( j = i - 1; j >= 0&& key<nums[j]; j--){
                nums[j + 1] = nums[j];
        }
        nums[j + 1] = key;
    }

}

/*
5.希尔排序(ShellSort )是插入排序的一种,是对直接插入排序算法的 改进该方法又称为缩小增量
排序。比较相距一定间隔的元素,即形如L[i,i+d,i+2d,…,i+kd]的序列然后缩小间距,再对各分组序列进行排序。直到之比较相邻元素的最后一趟排序为止,即最后的间距为1。
这里写图片描述
代码如下:
*/

//希尔排序
void ShellSort(vector<int> & nums){

    int n = nums.size();
    int i, j, tmp;
    int  d = n / 2;
    while (d >= 1){
    //对每组进行直接插入排序
        for (int i = d; i < n; ++i){
            tmp = nums[i];
            for (j = i - d; j >= 0 && tmp < nums[j]; j -= d){
                nums[j + d] = nums[j];
            }
            nums[j + d] = tmp;

        }
        d /= 2;
    }
}

/*

6.合并排序
合并排序采用分治算法,思路是将两个或以上的有序表合并为一个有序表,把
待排序的序列分割成若干个子序列,每个子序列有序,然后再把子序列合并为
一个有序序列。若将两个有序表合并成一个有序表,则成为2路合并排序。
2-路归并即使将2个有序表组合成一个新的有序表。假定待排序表有n个元素,
则可以看成是n个有序的字表,每个子表长度为1,然后两两归并…不停重复,
直到合并成一个长度为n的有序列表为止。Merge()函数是将前后相邻的两个有
序表归并为一个有序表,设A[low…mid]和A[mid+1…high]存放在同一顺序表
的相邻位置上,先将他们复制到辅助数组B中,每次从对应B中的两个段取出一
个元素进行比较,将较小者放入A中。
这里写图片描述

代码如下:

*/

//归并排序
//将两个有序的序列nums[low...mid] nums[mid...hight]合并
void mMerge(vector<int>&nums, int left, int mid, int right){
    int k = right - left + 1;
    vector<int> tmpArray(k);
    int p = right, q = mid;
    while (p > mid&& q >= left){
        if (nums[p] > nums[q]){
            tmpArray[--k] = nums[p--];
        }
        else{
            tmpArray[--k] = nums[q--];
        }
    }
    while (p > mid){
        tmpArray[--k] = nums[p--];
    }
    while (q >= left){
        tmpArray[--k] = nums[q--];
    }

    k = right - left + 1;
    for (int i = 0; i < k; i++){

        nums[left + i] = tmpArray[i];
    }

}
//折半法,即分治思想
void mymergeSort(vector<int>& nums, int left, int right){
    if (left < right){
        int mid = left + (right - left) / 2;
        mymergeSort(nums, left, mid);
        mymergeSort(nums, mid + 1, right);
        mMerge(nums, left, mid, right);
    }
}
void MergeSort(vector<int>& nums){
    int n = nums.size();
    mymergeSort(nums, 0, n - 1);
}

/*

7.堆排序
堆排序是一种属性选择排序方法,在排序过程中,将L[n]看成是一颗完全二叉树的顺序存储结构,利用完全
二叉中双亲节点和孩子节点之间的内在关系,在当前无序区中选择关键字最大(或最小)的元素。堆排序
的思路是:首先将序列L[n]的n个元素建成初始堆,由于堆本身的特点(以大根堆为例),堆顶元素就是最大
值。输出堆顶元素后,通常将堆底元素送入堆顶,此时根节点已不满足大根堆的性质,堆被破坏,将堆顶元
素向下调整使其继续保持大根堆的性质,再输出堆顶元素。如此重复,直到堆中仅剩下一个元素为止。

这里写图片描述

//代码如下:
*/

//堆排序
//使用数组二叉树,数组实现的堆中,第N个节点的左孩子的索引值是
void HeapAdjust(vector<int>&nums, int root, int size){

    //左孩子
    int leftChild = 2 * root + 1;
    //若有左孩子
    if (leftChild <= size - 1){
        //右孩子
        int rightChild = leftChild + 1;
        //若有右孩子
        if (rightChild <= size - 1){
            if (nums[leftChild] < nums[rightChild]){
                leftChild = rightChild;
            }
        }

        if (nums[root] < nums[leftChild]){
            swap(nums[root], nums[leftChild]);
            HeapAdjust(nums, leftChild, size);
        }
    }
}
void HeapSort(vector<int>& nums){

    int size = nums.size();
    for (int i = size / 2 - 1; i >= 0; --i){

        HeapAdjust(nums, i, size);
    }

    for (int i = size - 1; i>0; --i){

        swap(nums[0], nums[i]);
        HeapAdjust(nums, 0, i);
    }
}

/*
8.基数排序
它是一种非比较排序。它是根据位的高低进行排序,也就是先按照个位排序然后按照十位
排序……依次类推。示例如下:
这里写图片描述

代码如下:
*/

/*基数排序*/
void RadixSort(vector<int> &array)
{
    int size = array.size();
    int bucket[10][10] = { 0 };//定义基数桶  
    int order[10] = { 0 };//保存每个基数桶之中的元素个数  
    int key_size = KeySize(array);//计算关键字位数的最大值  

    for (int n = 1; key_size>0; n *= 10, key_size--)
    {
        /*将待排序的元素按照关键值的大小依次放入基数桶之中*/
        for (int i = 0; i<size; i++)
        {
            int lsd = (array[i] / n) % 10;
            bucket[lsd][order[lsd]] = array[i];
            order[lsd]++;
        }

        /*将基数桶中的元素重新串接起来*/
        int k = 0,i;
        for (i = 0; i<10; i++)
        {
            if (order[i] != 0)
            {
                for (int j = 0; j<order[i]; j++)
                {
                    array[k] = bucket[i][j];
                    k++;
                }
                order[i] = 0;
            }
        }
    }
}

int main(){
    vector<int> nums{25,54,34,922,134,778};
    RadixSort(nums);
    for (auto a : nums){
        cout << a << " ";
    }
    cout << endl;
    return 0;

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++实现——排序算法总结 的相关文章

  • 如何将一组重叠范围划分为不重叠范围?

    假设您有一组范围 0 100 一 0 75 b 95 150 c 120 130 d 显然 这些范围在某些点上重叠 您将如何剖析这些范围以生成不重叠范围的列表 同时保留与其原始范围相关的信息 在本例中为范围后面的字母 例如 运行算法后的上述
  • 如何求小于给定数的最大2次方

    我需要找到小于给定数字的最大 2 次幂 我陷入困境 找不到任何解决方案 Code public class MathPow public int largestPowerOf2 int n int res 2 while res lt n
  • 将字符串中的“奇怪”字符转换为罗马字符

    我需要能够将用户输入仅转换为 a z 罗马字符 不区分大小写 所以 我感兴趣的角色只有26个 然而 用户可以输入他们想要的任何 形式 的字符 西班牙语 n 法语 e 和德语 u 都可以包含用户输入中的重音符号 这些重音符号会被程序删除 我已
  • 如何仅使用单个数组在 JavaScript 中模拟调用堆栈

    我正在看维基百科页面 https en wikipedia org wiki Call stack在调用堆栈上 并尝试理解这个图像 据我所知 哈哈 const memory memory 0 3 top of stack pointer m
  • 使用并集查找(又名不相交集)检测图是否是二分图

    我正在 Spoj 上做一个问题 基本上可以简化为检测图是否是二分图 我正在尝试使用 dfs 为图表着色 但它太慢了 有人评论这个 没有 bfs 没有 dfs 没有二部图 简单的并查集就可以做到 确实速度很快 提示 1 偶数长度的环不会影响两
  • 如何检查是否存在可能的路径?

    我正在开发一个基于 javascript 的实验性游戏 玩家必须在二维平铺地图上移动才能退出 请随意检查这个小提琴并演奏 http jsfiddle net moonlife 74vLd 我只是随机放置障碍物 但有时障碍物会挡住玩家和出口之
  • 迭代任意大小的子集

    我可以迭代大小为 1 的子集 for int a 0 a lt size a 或大小为 2 的子集 for int a1 0 a1 lt size a1 for int a2 a1 1 a2 lt size a2 or 3 for int
  • 具有 2 个属性的背包算法。如何在 3d 数组中实现它?

    当有超过 1 个属性时 我无法理解背包问题 当有 1 个属性时 我必须编写一个使用具有 2 个属性的背包算法的程序 老师告诉我们 它必须在 3d 数组中完成 错误的实现将导致 O 2 n 处理时间 我无法想象这样的数组会是什么样子 假设这是
  • 如何从迭代器推导连续内存

    不知何故 本土stl copy VC Dinkumware 上的算法表明它可以使用memcpy 可以轻松复制的数据 一个凡人能做到这一点吗 假设每个元素都是普通可复制的 random access iterator 是否意味着连续内存 标准
  • 大数据使用什么数据结构

    我有一个包含一百万行的 Excel 工作表 每行有 100 列 每行代表一个具有 100 个属性的类的实例 列值是这些属性的值 哪种数据结构最适合在这里使用来存储数百万个数据实例 Thanks 这实际上取决于您需要如何访问这些数据以及您想要
  • 解开 Knuth 的结:如何重构意大利面条式代码?

    这个问题的灵感来自如何将流程图转化为实施 https stackoverflow com questions 36647765它询问如何通过算法消除goto代码中的语句 这answer https stackoverflow com a 3
  • 如何用约束标记一大组“传递群”?

    在 NealB解决方案之后进行编辑 与以下解决方案相比 NealB的解决方案非常非常快任何另一个 https stackoverflow com q 18033115 answers and 提出了关于 添加约束以提高性能 的新问题 Nea
  • 照片马赛克算法。如何在给定基本图像和瓷砖列表的情况下创建马赛克照片?

    Hy 我要做的是创建一个程序 使用 C 或 C 它将 24 位 像素位图和图像集合作为输入 我必须创建一个马赛克图像 类似于使用库的输入图像给定的图像 创建与输入类似的马赛克照片 到目前为止 我可以访问输入的图像像素及其颜色 但我有点卡住了
  • 平铺单纯形噪声?

    我 作为业余爱好者 对伪随机噪声生成很感兴趣 特别是 Perlin 和 Simplex 算法 Simplex 的优点是速度 尤其是在更高的维度上 但 Perlin 可以相对容易地平铺 我想知道是否有人知道平铺单纯形算法 固定维度就好 泛型更
  • Prim 的迷宫生成算法:获取相邻单元格

    我基于 Prim 算法编写了一个迷宫生成器程序 该算法是 Prim 算法的随机版本 从充满墙壁的网格开始 选择一个单元格 将其标记为迷宫的一部分 将单元格的墙壁添加到墙壁列表中 While there are walls in the li
  • 应用对数来导航树

    我曾经知道一种使用对数从树的一片叶子移动到树的下一个 有序 叶子的方法 我认为它涉及获取 当前 叶子的位置值 排名 并将其用作从根向下到新目标叶子的新遍历的种子 一直使用对数函数测试来确定是否沿着右或左节点向下到达叶子 我已经不记得如何运用
  • AStar-名称解释

    我正在寻找 AStar A 算法为何被称为 AStar 的解释 所有类似的 最短路径问题 算法通常都以其开发者的名字命名 那么 AStar 代表什么 有称为 A1 和 A2 的算法 后来证明A2是最优的 实际上也是可能的最好算法 所以他给它
  • 如何使用 python 有效地找到两个大文件的交集?

    我有两个大文件 它们的内容如下所示 134430513125296589151963957125296589 该文件包含未排序的 id 列表 某些 id 可能会在单个文件中出现多次 现在我想找到路口两个文件的一部分 这就是两个文件中都出现的
  • 如何从 Trie 中检索给定长度的随机单词

    我有一个简单的 Trie 用来存储大约 80k 长度为 2 15 的单词 它非常适合检查字符串是否是单词 但是 现在我需要一种获取给定长度的随机单词的方法 换句话说 我需要 getRandomWord 5 来返回 5 个字母的单词 所有 5
  • pytesseract 无法从图像中识别复杂的数学公式

    我在用pytesseractpython 中的模块 pytesseract从图像中识别文本 但它不适用于包含复杂数学公式 例如根 推导 积分数学问题或方程 的图像 代码2 py Import modules from PIL import

随机推荐

  • 【unity3D】TimeLine(详细图解)

    未来的游戏开发程序媛 现在的努力学习菜鸡 本专栏是我关于游戏开发的学习笔记 本篇关于unity的TimeLine TimeLine 介绍 打开TimeLine面板的方式 创建TimeLine 创建Track的两种方式 Track的详解 Ti
  • win10使用技巧02--系统端口被占用怎么查看

    1 打开命令提示符 管理员模式 2 输入netstat ano命令 回车后 能看到所有端口的情况 3 如果我们知道具体的端口号的话 输入netstat aon findstr 8080 其中8080加英文双引号 按回车键就可以找到占用808
  • Spark环境搭建(保姆级教程)

    文章目录 一 环境准备 二 Spark环境搭建 1 Spark部署方式 2 安装spark 1 下载Spark 关于版本的选择 2 安装Spark 上传安装包 解压并创建软链接 Spark的目录结构 配置环境变量 配置Hadoop信息 修改
  • 飞行姿态解算(三)

    继之前研究了一些飞行姿态理论方面的问题后 又找到了之前很流行的一段外国大神写的代码 来分析分析 第二篇文章的最后 讲到了文章中的算法在实际使用中有重大缺陷 大家都知道 分析算法理论的时候很多情况下我们没有考虑太多外界干扰的情况 原因是很多情
  • CSS响应式设计——(视口/网格视图/媒体查询/图像/视频)看这一篇就够了

    目录 响应式网页设计 简介 什么是响应式网页设计 为所有用户获得最佳体验的设计 响应式网页设计 视口 什么是视口 设置视口 把内容调整到视口的大小 响应式网页设计 网格视图 什么是网格视图 构建响应式网格视图 实例 CSS CSS HTML
  • windows 使用 wget——Wget for windows

    wget是一个强力方便的命令行下的下载工具 windows 如果使用需要安装 Wget for windows 地址 Link 下载压缩包 ZIP 解压到一个常用的安装位置 然后按照下面的步骤 配置环境变量 系统属性 此电脑右击选择属性 左
  • Vim安装配置和常用技巧

    第一章 安装 在命令行运行vim 如果找不到程序 需要自己安装 1 1 下载 从官方网站ftp ftp vim org pub vim unix 中选择一个版本下载 我这里使用的是vim 7 3 tar bz2 1 2 解压程序 tar x
  • 如何用js动态添加css

    转自 微点阅读 https www weidianyuedu com 为了节省代码和写出更兼容的代码 有时我们需要用Javascript动态的增加CSS样式 IE下 我们可以使用 document createStyleSheet 方法 而
  • C/C++实现strstr函数、KMP算法查找子串

    C C 实现strstr KMP算法查找子串 目录 C C 实现strstr KMP算法查找子串 1 字符串形式 2 字节流形式 1 字符串形式 代码实现 char my strstr const char src const char d
  • 反射改进简单工厂(含代码)

    一 简单工厂代码 父类Car public class Car public void CreateCar 子类ElectricityCar public class ElectricityCar extends Car Override
  • 使用mysql数据库与go进行交互

    database sql database sql是golang的标准库之一 它提供了一系列接口方法 用于访问关系数据库 它并不会提供数据库特有的方法 那些特有的方法交给数据库驱动去实现 database sql库提供了一些type 这些类
  • 线性代数(2)——矩阵

  • [完]机器学习实战 第十四章 利用SVD简化数据

    本章内容 SVD矩阵分解 推荐引擎 利用SVD提升推荐引擎的性能 餐馆可分为很多类别 不同的专家对其分类可能有不同依据 实际中 我们可以忘掉专家 从数据着手 可对记录用户关于餐馆观点的数据进行处理 并从中提取出其背后的因素 这些因素可能会与
  • 快速排序算法 (c/c++)

    快速排序 QuickSort Code 1 中间元素为基准 Code 1示例结果 Code 2 第一元素为基准 Code 2示例结果 算法分析 QuickSort 通过一趟排序将要排序的数据分隔成独立的两部分 其中一部分的所有数据都要比另一
  • Mental ray 渲染器常用设置

    Mental ray 渲染器常用设置 Mental ray是一个专业的3D渲染引擎 它可以生成令人难以置信的高质量真实感图象 现在你可以在3D Studio的高性能网络渲染中直接控制Mental ray 它在电影领域得到了广泛的应用和认可
  • 用python怎样做学生管理系统用类的形式-Python配置管理的几种方式

    一 为什么要使用配置 如果我们在较复杂的项目中不使用配置文件 我们可能会面临下面的情况 你决定更改你的项目中数据库的 host 因为你要将项目从测试环境转移到实际的上产环境中 如果你的项目中多个位置用到了这个 host 那你不得不一个一个找
  • CS336视觉伺服

    笔记 动力学模型 机械臂动力学的研究方法 拉格朗日 牛顿 欧拉 高斯 凯恩方法 机械臂的动力学主要是两个问题 正向运动学和逆向运动学 视觉伺服 视觉伺服的基本思想 基于视觉的伺服控制方法的目的是最小化一个图像误差 该误差可以定义为 e t
  • Elasticsearch搜索系统线上部署配置规划

    问题导读 1 es安装包的目录结构是怎样的 2 zen discovery集群发现机制的设置规划及其原理是怎样的 3 es默认参数调优如何进行 1 ES部署须知1 1 包结构es安装包的目录结构大致如下 bin 存放es的一些可执行脚本 比
  • Python数据分析之股票数据

    最近股市比较火 我7月初上车了 现在已经下了 中间虽然吃了点肉 但下车的时候都亏进去了 最后连点汤都没喝着 这篇文章我们就用python对股票数据做个简单的分析 数据集是从1999年到2016年上海证券交易所的1095只股票 共1000个文
  • C++实现——排序算法总结

    常见的排序算法有 直接插入 希尔 冒泡 快速 选择 堆排序 归并 基数 下面一一分析 并实现 1 冒泡排序 冒泡排序是最简单的排序算法 冒泡排序的基本思想是从后往前 或从前往后 两两比较相邻元素的值 若为逆序 则交换它们 直到序列比较完毕