数据结构与算法基础(王卓)(37):选择排序(简单选择、堆排序)

news2024/11/14 21:45:15

目录

简单选择排序

堆排序

堆的调整:

大根堆

小根堆

整个堆调整的完整工序如下:

 根据按照操作对程序注解标注:(看过了注解就知道程序他每一步是怎么操作的了)

堆的建立

问题


简单选择排序

#include<iostream>
using namespace std;

#define MAXSIZE 20  //记录最大个数
typedef int KeyType;  //关键字类型

typedef int InfoType;

//定义每个记录(数据元素)的结构
struct RecType
    //Record Type:每条记录的类型
{
    KeyType key;  //关键字
    InfoType otherinfo;  //其他数据项
};

struct SqList
    //顺序表(的)结构
{
    RecType r[MAXSIZE + 1];
    //类型为【记录类型】的数组
    //r[0]一般做哨兵或缓冲区
    int length;  //顺序表长度
};

void SelectSort(SqList& L)
{
    for (int i = 1; i <= L.length; i++)
    {
        int k = L.r[i].key;
        for (int j = i; j <= L.length; j++)
        {
            if (L.r[j].key < k)
                k = L.r[j].key;
        }
        if (k != L.r[i].key)
        {
            int temp = L.r[i].key;
            L.r[i].key = k;
            k = temp;
        }
    }
}


int main()
{

}


堆排序


堆的调整:

大根堆

void HeapAdjust(Elem R[], int s, int m) //Heap:堆
//二叉树空间范围:s-m,这里写的是大根堆
// s:smallest
// m:max
{
    //调整R[s]的关键字,使R[s...m]重新成为一个大根堆
    Elem rc = R[s];
    for (int j = 2 * s; j <= m; j *= 2)
    {
        if (j < m && R[j] < R[j + 1])
            j++;  //j为关键字较大的数据元素下标
        if (rc >= R[j])
            break;
        R[s] = R[j];
        s = j;  //记录位置
    }
    R[s] = rc;  //插入
}

在一开始(最开始),我们看这个程序,那是根本完全看不懂,艹

我们甚至还提出了问题:他这里是怎么找到最后一个元素的???我怎么没看出来呀

于是就先依葫芦画瓢先造出/想办法搞出一个小根堆来试试:

小根堆

void HeapAdjust(Elem R[], int s, int m) //小根堆
{
    Elem rc = R[s];
    for (int j = 2 * s; j <= m; j *= 2)
    {
        if (j < m && R[j] > R[j + 1])
            j++;  //j为关键字较小的数据元素下标
        if (rc <= R[j])
            break;
        R[s] = R[j];
        s = j;  //记录位置
    }
    R[s] = rc;  //插入
}

然后我们对着程序沉默死磕半天,终于咂摸着知道这东西写的是啥玩意了:

整个堆调整的完整工序如下:

而这里(实际上我们这里):

PPT实际上写的其实是步骤二(图2)到步骤四(图4)这个整个过程的算法

而不是tmd从图1开始的整个过程的算法

程序开始时他已经默认完前面从图1到图2的过程操作已经给我们提前安排操作好了

TMD!

 根据按照操作对程序注解标注:(看过了注解就知道程序他每一步是怎么操作的了)

以小根堆为例:(大根堆同理,这里就不再赘述)

void HeapAdjust(Elem R[], int s, int m) //小根堆
{
    Elem rc = R[s];
    //此时最后的元素已经被放到堆顶,rc记录最后一位元素
    for (int j = 2 * s; j <= m; j *= 2)
        //从第二层子树开始遍历
    {
        if (j < m && R[j] > R[j + 1])
            j++; 
        //j:关键字较小的元素下标
        if (rc <= R[j])
            break;
        //要最后一个元素比他小就算了,不然的话:
        R[s] = R[j];
        //j(较小)元素放上面去
        s = j;  
        //下一轮for循环:
        //从上一轮j的位置开始往下遍历
        //以j的位置为根,向下遍历子树,不断把值小的元素移上去
    }
    R[s] = rc; 
    //最后,把最后的元素插入到最底部
    // 注:
    // 最后退出循环的时候s已经指向最底层了
    // 而不出意外的话,最后的元素理论上也应该是堆里面最大的一个元素
}

堆的建立

#include<iostream>
using namespace std;

typedef int Elem;

void HeapAdjust(Elem R[], int s, int m) //小根堆
{
    Elem rc = R[s];
    //此时最后的元素已经被放到堆顶,rc记录最后一位元素
    for (int j = 2 * s; j <= m; j *= 2)
        //从第二层子树开始遍历
    {
        if (j < m && R[j] > R[j + 1])
            j++; 
        //j:关键字较小的元素下标
        if (rc <= R[j])
            break;
        //要最后一个元素比他小就算了,不然的话:
        R[s] = R[j];
        //j(较小)元素放上面去
        s = j;  
        //下一轮for循环:
        //从上一轮j的位置开始往下遍历
        //以j的位置为根,向下遍历子树,不断把值小的元素移上去
    }
    R[s] = rc; 
    //最后,把最后的元素插入到最底部
    // 注:
    // 最后退出循环的时候s已经指向最底层了
    // 而不出意外的话,最后的元素理论上也应该是堆里面最大的一个元素
}

void Swap(int a, int b)
{
    int temp=b;
    b = a;
    a = temp;
}

void HeapSort(Elem R[],int n)
{
    int i;
    for (i = n / 2; i >= 1; i--)  
        HeapAdjust(R, i, n);
    // 我们默认R[]数据无序
    // 先把R[]中的无序数据都排一遍顺序
    // 相当于我们先构造出一个合格的图1

    for (i = n; i > 1; i--)
    {
        cout << R[1] << endl;//逐个输出元素
        Swap(R[1], R[i]);  
        //互换最后一个元素和根
        //相当于执行图1加工到图2的过程

        HeapAdjust(R, 1, i - 1); 
        //面向剩下的元素重新建堆
    }
}

int main()
{

}

​​​​​​​

问题:

 至于最后一个元素和根互换以后会不会影响到程序结果,这种担心我们大可不必:

当我们排序小根堆时:

最后的元素,也就是最大的元素,必定在二叉树子树数值大的那一侧

而我们后续遍历排序改动的、则是二叉树子树数值小的那一侧,所以必然没有影响

大根堆同理,不再赘述

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

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

相关文章

Feign踩坑源码分析--@FeignClient注入容器

一. EnableFeignClients 1.1.类介绍 从上面注释可以看出是扫描声明了FeignClient接口的类&#xff0c;还引入了 FeignClientsRegistrar类&#xff0c;从字面意思可以看出是进行了 FeignClient 客户端类的注册。 1.2.FeignClientsRegistrar 详解 最主要的一个方法&#xff1a;re…

喜报丨酷雷曼荣膺最佳创新品牌价值奖

2023年4月&#xff0c;“元力觉醒新浪VR 2022年度行业奖项”颁奖盛典成功举行&#xff0c;酷雷曼VR&#xff08;北京同创蓝天云科技有限公司&#xff09;荣获“最佳创新品牌价值奖”荣誉称号&#xff01; 本次大会由元宇宙产业的权威门户媒体新浪VR主办&#xff0c;中国民协元…

从入门到精通:网络爬虫开发实战总结

从入门到精通&#xff1a;网络爬虫开发总结 专栏&#xff1a;Python网络爬虫1.认识网络爬虫2.网络爬虫——HTML页面组成3.网络爬虫——Requests模块get请求与实战4.网络爬虫—Post请求(实战演示)5.网络爬虫——Xpath解析6.网络爬虫——BeautifulSoup详讲与实战7.网络爬虫—正则…

网络原理(五):IP 协议

目录 认识IP 地址 子网掩码 作用 动态分配IP 地址 NAT 机制 认识MAC地址 MAC地址如何工作 认识IP 地址 概念&#xff1a; IP地址&#xff08;Internet Protocol Address&#xff09;是指互联网协议地址&#xff0c;又译为网际协议地址。 作用&#xff1a; IP地址是I…

遗传算法(GA)

理论&#xff1a; 遗传算法是一种通过模拟生物进化的方式来寻找最优解的一类优化算法。这种算法主要依靠遗传、突变和自然选择的机制对问题求解进行高效的迭代搜索。 遗传算法的基本思想是将问题的解表示成一个个个体&#xff0c;然后根据适应度函数的定义来评估每个个体的适…

【数组排序算法】

目录 一、数组排序算法1、冒泡排序算法1.1、图形解释1.2、冒泡算法的脚本写法 二、直接选择排序1.1、动态图解1.2、直接选择排序算法的脚本编写 三、直接插入排序1.1、基本思想&#xff1a;1.2、动态图解1.3、直接插入排序的算法脚本编写 四、反向序列算法1.1、反向序列算法的脚…

linux:文件替换的三种方式sed、awk、perl

文章目录 背景sed语法问题1、加个空字符串2、下载gnu-sed awk语法举例 perl语法示例 总结 背景 linux 文件内容替换&#xff0c;网上看了下大致就这三种 sed、awk、perl&#xff0c;今天挨个使用一下看看怎么样 sed 语法 Linux sed 命令是利用脚本来处理文本文件。详细文档…

网络基础认知(上)

如今使用过计算机的人们都接触过网络&#xff0c;但是网络究竟是什么&#xff0c;计算机又是怎样通过网络来进行互相之间通信的&#xff0c;这还需要我们深入了解。 目录 网络发展 初识协议 什么是协议 为什么需要协议&#xff1f; 网络协议初识 协议分层 为什么网络协议要…

澳鹏与Reka AI强强联合,构建高质量的多模态LLM应用

近日&#xff0c;澳鹏Appen官宣与AI新兴公司Reka AI合作&#xff0c;以实现世界级数据服务与多模态语言模型的结合。 ChatGPT等创新应用的崛起让大型语言模型&#xff08;LLM&#xff09;实现了突飞猛进的发展。LLM可以助力企业提升运营效率&#xff0c;并为最终用户提供耳目一…

Java基础--->JVM(3)【垃圾回收】

文章目录 垃圾回收&#xff08;GC&#xff09;什么内存需要回收&#xff08;什么样的对象是垃圾&#xff09;&#xff1f;为什么要进行垃圾回收&#xff1f;内存溢出和内存泄露的区别&#xff0c;如何解决分区收集思想 Minor GC、Major GC、Full GC垃圾回收相关算法引用计数算法…

如何搭建产品操作手册

对于企业来说&#xff0c;拥有一份完备的产品操作手册无疑是至关重要的。操作手册不仅是新员工学习产品使用及维护的重要参考&#xff0c;也是产品售后服务与客户支持的必备文件。在手册编写上&#xff0c;应清晰明了地介绍产品的功能、配置及故障排除等信息&#xff0c;使用户…

统计学下的假设检验

由于本人才疏学浅&#xff0c;再加上时间仓促&#xff0c;难免有疏漏之处&#xff0c;恳请批评指正. 1,预备知识 数理统计&#xff1a;以概率论为基础&#xff0c;研究如何有效的去搜集、整理、分析带随机性影响的数据 总体与样本&#xff1a;研究对象的全体就称为总体 样本&a…

VTK交互-vtkBoxWidget2

VTK交互Widget widget包含两个重要的组成部分&#xff1a;Interaction和Representation. Interaction是一些名叫vtk*Widget的类&#xff08;比如vtkBoxWidget2&#xff09;。它包含了交互的所有选项和事件处理。 Representation是显示并与之交互的一类对象&#xff0c;以名叫v…

origin 拟合计算酶的Kcat Km 值

origin拟合计算Kcat Km值 横坐标为底物浓度&#xff0c;纵坐标为反应速率 全选X 与Y坐标数据&#xff0c;然后选择菜单栏Analysis: Fitting: Nonlinear Curve Fit&#xff1a;Open Dialog 在Setting&#xff1a;Function Selection页面内的Category选择Pharmacology, Functi…

计算机网络基础知识(三)—— 什么是OSI七层模型?

文章目录 00 | &#x1f6f8;发展史&#x1f6f8;01 | &#x1f6f8;OSI七层参考模型&#x1f6f8;02 | &#x1f6f8;OSI七层参考模型的信息流向&#x1f6f8; OSI七层模型是Open Systems Interconnection Reference Model的缩写&#xff0c;是由国际标准化组织&#xff08;IS…

vue3使用keep-alive组件,包含动态组件使用

vue3使用keep-alive组件&#xff0c;包含动态组件使用 本文目录 vue3使用keep-alive组件&#xff0c;包含动态组件使用组件不使用keep-alive组件中使用v-if切换component动态组件切换因注释导致的意外错误动态组件的使用完整示例 路由不使用keep-alive路由中使用keep-alive生命…

公司数字化转型,如何选择高效的知识管理工具?

随着企业数字化转型的加速&#xff0c;知识管理工具的重要性也日益凸显。好的知识管理工具可以帮助企业提高工作效率、降低成本、提高创新能力和竞争力。但是&#xff0c;市场上的知识管理工具繁多&#xff0c;如何选择高效的知识管理工具成为了企业面临的一大难题。本文将从以…

Jenkins 入门系列之Role-based Strategy配置Gitlab Group管理用户组

目录 背景步骤1. 安装插件2. 配置Gitlab Group3. 配置 Jenkins 授权策略4. 配置 Jenkins 角色与授权5. 验证 背景 版本 Jenkins Version&#xff1a;Jenkins 2.403Gitlab Version: Gitlab 15.6部署环境&#xff1a;群晖NAS Docker 部署JenkinsGitlab 上一篇文章Jenkins 入门…

HTML详解

HTML是什么 html是一门语言&#xff0c;所有的网页都是用它编写出来的。 他是一门超文本标记语言。可以定义图片&#xff0c;音频&#xff0c;视频等。由标签组成。 HTMl仅仅定义了网站的接口。 具体的表现还需要css来实现&#xff0c;也就是css让网页变得更加好看。 网页…

智能聊天机器人ChatGPT商业版

作为一个智能聊天机器人&#xff0c;我是由OpenAI开发的。目前&#xff0c;我的商业版需要通过OpenAI的合作伙伴计划进行许可和部署&#xff0c;以确保我被用于适当的商业用途。如果您对商业使用感兴趣&#xff0c;请联系OpenAI以获取更多信息。 智能聊天机器人是一种能够自…