C#【进阶】排序进阶

排序进阶

文章目录

      • 插入排序
      • 希尔排序
      • 归并排序
      • 快速排序
      • 堆排序

插入排序

在这里插入图片描述


#region 知识点一 插入排序的基本原理
// 8 7 1 5 4 2 6 3 9
// 两个区域
// 排序区
// 未排序区
// 用一个索引值做分水岭// 未排序区元素
// 与排序区元素比较
// 插入到合适位置
// 直到未排序区清空
#endregion#region 知识点二 代码实现
//实现升序 把 大的 放在最后面
int[] arr = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };//前提规则
//排序开始前
//首先认为第一个元素在排序区中
//其它所有元素在未排序区中//排序开始后
//每次将未排序区第一个元素取出用于和
//排序区中元素比较(从后往前)
//满足条件(较大或者较小)
//则排序区中元素往后移动一个位置。//注意
//所有数字都在一个数组中
//所谓的两个区域是一个分水岭索引//第一步
//能取出未排序区的所有元素进行比较
//i=1的原因:默认第一个元素就在排序区
for (int i = 1; i < arr.Length; i++)
{//第二步//每一轮//1.取出排序区的最后一个元素索引int sortIndex = i - 1;//2.取出未排序区的第一个元素int noSortNum = arr[i];//第三步//在未排序区进行比较//移动位置//确定插入索引//循环停止的条件//1.发现排序区中所有元素都已经比较完//2.发现排序区中的元素不满足比较条件了while (sortIndex >= 0 &&arr[sortIndex] > noSortNum){//只要进了这个while循环 证明满足条件//排序区中的元素 就应该往后退一格arr[sortIndex + 1] = arr[sortIndex];//移动到排序区的前一个位置 准备继续比较--sortIndex;}//最终插入数字//循环中知识在确定位置 和找最终的插入位置//最终插入对应位置 应该循环结束后arr[sortIndex + 1] = noSortNum;
}for (int i = 0; i < arr.Length; i++)
{Console.WriteLine(arr[i]);
}
#endregion#region 知识点三 总结//为什么有两层循环
//第一层循环:一次取出未排序区的元素进行排序
//第二层循环:找到想要插入的位置//为什么第一层循环从1开始遍历
//插入排序的关键是分两个区域
//已排序区 和 未排序区
//默认第一个元素在已排序区//为什么使用while循环
//满足条件才比较
//否则证明插入位置已确定
//不需要继续循环//为什么可以直接往后移位置
//每轮未排序数已记录
//最后一个位置不怕丢//为什么确定位置后,是放在sortIndex + 1的位置
//当循环停止时,插入位置应该是停止循环的索引加1处//基本原理
//两个区域
//用索引值来区分
//未排序区与排序区
//元素不停比较
//找到合适位置
//插入当前元素//套路写法
//两层循环
//一层获取未排序区元素
//一层找到合适插入位置//注意事项
//默认开头已排序
//第二层循环外插入#endregion

希尔排序

在这里插入图片描述

#region 知识点一 希尔排序的基本原理
//希尔排序是
//插入排序的升级版
//必须先掌握插入排序//希尔排序的原理
//将整个待排序序列
//分割成为若干子序列
//分别进行插入排序//总而言之
//希尔排序对插入排序的升级主要就是加入了一个步长的概念
//通过步长每次可以把原序列分为多个子序列
//对子序列进行插入排序
//在极限情况下可以有效降低普通插入排序的时间复杂度
//提升算法效率
#endregion#region 知识点二 代码实现
int[] arr = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };
//学习希尔排序的前提条件 
//先掌握插入排序
//第一步:实现插入排序
//第一层循环 是用来取出未排序区中的元素的
//for (int i = 1; i < arr.Length; i++)
//{
//    //得出未排序区的元素
//    int noSortNum = arr[i];
//    //得出排序区中最后一个元素索引
//    int sortIndex = i - 1;
//    //进入条件
//    //首先排序区中还有可以比较的 >=0
//    //排序区中元素 满足交换条件 升序就是排序区中元素要大于未排序区中元素
//    while (sortIndex >= 0 &&
//        arr[sortIndex] > noSortNum)
//    {
//        arr[sortIndex + 1] = arr[sortIndex];
//        --sortIndex;
//    }
//    //找到位置过后 真正的插入 值
//    arr[sortIndex + 1] = noSortNum;
//}//for (int i = 0; i < arr.Length; i++)
//{
//    Console.WriteLine(arr[i]);
//}//第二步:确定步长
//基本规则:每次步长变化都是/2
//一开始步长 就是数组的长度/2
//之后每一次 都是在上一次的步长基础上/2
//结束条件是 步长 <=0 
//1.第一次的步长是数组长度/2  所以:int step = arr.length/2
//2.之后每一次步长变化都是/2  索引:step /= 2
//3.最小步长是1  所以:step > 0
for (int step = arr.Length / 2; step > 0; step /= 2)
{//注意://每次得到步长后 会把该步长下所有序列都进行插入排序//第三步:执行插入排序//i=1代码 相当于 代表取出来的排序区的第一个元素//for (int i = 1; i < arr.Length; i++)//i=step 相当于 代表取出来的排序区的第一个元素for (int i = step; i < arr.Length; i++){//得出未排序区的元素int noSortNum = arr[i];//得出排序区中最后一个元素索引//int sortIndex = i - 1;//i-step 代表和子序列中 已排序区元素一一比较int sortIndex = i - step;//进入条件//首先排序区中还有可以比较的 >=0//排序区中元素 满足交换条件 升序就是排序区中元素要大于未排序区中元素while (sortIndex >= 0 &&arr[sortIndex] > noSortNum){//arr[sortIndex + 1] = arr[sortIndex];// 代表移步长个位置 代表子序列中的下一个位置arr[sortIndex + step] = arr[sortIndex];//--sortIndex;//一个步长单位之间的比较sortIndex -= step;}//找到位置过后 真正的插入 值//arr[sortIndex + 1] = noSortNum;//现在是加步长个单位arr[sortIndex + step] = noSortNum;}
}for (int i = 0; i < arr.Length; i++)
{Console.WriteLine(arr[i]);
}#endregion#region 知识点三 总结
//基本原理
//设置步长
//步长不停缩小
//到1排序后结束//具体排序方式
//插入排序原理//套路写法
//三层循环
//一层获取步长
//一层获取未排序区元素
//一层找到合适位置插入//注意事项
//步长确定后
//会将所有子序列进行插入排序
#endregion

归并排序

在这里插入图片描述

int[] arr = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };arr = Merge(arr);for (int i = 0; i < arr.Length; i++)
{Console.WriteLine(arr[i]);
}#region 知识点一 归并排序基本原理
//归并 = 递归 + 合并//数组分左右
//左右元素相比较
//满足条件放入新数组
//一侧用完放对面//递归不停分
//分完再排序
//排序结束往上走
//边走边合并
//走到头顶出结果//归并排序分成两部分
//1.基本排序规则
//2.递归平分数组//递归平分数组:
//不停进行分割
//长度小于2停止
//开始比较
//一层一层向上比//基本排序规则:
//左右元素进行比较
//依次放入新数组中
//一侧没有了另一侧直接放入新数组
#endregion#region 知识点二 代码实现//第一步:
//基本排序规则
//左右元素相比较
//满足条件放进去
//一侧用完直接放
static int[] Sort(int[] left, int[] right)
{//先准备一个新数组int[] array = new int[left.Length + right.Length];int leftIndex = 0;//左数组索引int rightIndex = 0;//右数组索引//最终目的是要填满这个新数组//不会出现两侧都放完还在进循环 //因为这个新数组的长度 是根据左右两个数组长度计算出来的for (int i = 0; i < array.Length; i++){//左侧放完了 直接放对面右侧if (leftIndex >= left.Length){array[i] = right[rightIndex];//已经放入了一个右侧元素进入新数组//所以 标识应该指向下一个嘛rightIndex++;}//右侧放完了 直接放对面左侧else if (rightIndex >= right.Length){array[i] = left[leftIndex];//已经放入了一个左侧元素进入新数组//所以 标识应该指向下一个嘛leftIndex++;}else if (left[leftIndex] < right[rightIndex]){array[i] = left[leftIndex];//已经放入了一个左侧元素进入新数组//所以 标识应该指向下一个嘛leftIndex++;}else{array[i] = right[rightIndex];//已经放入了一个右侧元素进入新数组//所以 标识应该指向下一个嘛rightIndex++;}}//得到了新数组 直接返回出去return array;
}//第二步:
//递归平分数组
//结束条件为长度小于2static int[] Merge(int[] array)
{//递归结束条件if (array.Length < 2)return array;//1.数组分两段  得到一个中间索引int mid = array.Length / 2;//2.初始化左右数组//左数组int[] left = new int[mid];//右数组int[] right = new int[array.Length - mid];//左右初始化内容for (int i = 0; i < array.Length; i++){if (i < mid)left[i] = array[i];elseright[i - mid] = array[i];}//3.递归再分再排序return Sort(Merge(left), Merge(right));
}
#endregion#region 知识点三 总结
//理解递归逻辑
//一开始不会执行Sort函数的
//要先找到最小容量数组时
//才会回头递归调用Sort进行排序//基本原理
// 归并 = 递归 + 合并
// 数组分左右
// 左右元素相比较
// 一侧用完放对面
// 不停放入新数组//递归不停分
//分完再排序
//排序结束往上走
//边走边合并
//走到头顶出结果//套路写法
//两个函数
//一个基本排序规则
//一个递归平分数组//注意事项
//排序规则函数 在 平分数组函数
//内部 return调用#endregion

快速排序

在这里插入图片描述

int[] arr = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };
QuickSort(arr, 0, arr.Length - 1);for (int i = 0; i < arr.Length; i++)
{Console.WriteLine(arr[i]);
}#region 知识点一 快速排序基本原理
//选取基准
//产生左右标识
//左右比基准
//满足则换位//排完一次
//基准定位//左右递归
//直到有序
#endregion#region 知识点二 代码实现
//第一步:
//申明用于快速排序的函数
static void QuickSort(int[] array, int left, int right)
{//第七步://递归函数结束条件if (left >= right)return;//第二步://记录基准值//左游标//右游标int tempLeft, tempRight, temp;temp = array[left];tempLeft = left;tempRight = right;//第三步://核心交换逻辑//左右游标会不同变化 要不相同时才能继续变化while (tempLeft != tempRight){//第四步:比较位置交换//首先从右边开始 比较 看值有没有资格放到表示的右侧while (tempLeft < tempRight &&array[tempRight] > temp){tempRight--;}//移动结束证明可以换位置array[tempLeft] = array[tempRight];//上面是移动右侧游标//接着移动完右侧游标 就要来移动左侧游标while (tempLeft < tempRight &&array[tempLeft] < temp){tempLeft++;}//移动结束证明可以换位置array[tempRight] = array[tempLeft];}//第五步:放置基准值//跳出循环后 把基准值放在中间位置//此时tempRight和tempLeft一定是相等的array[tempRight] = temp;//第六步://递归继续QuickSort(array, left, tempRight - 1);QuickSort(array, tempLeft + 1, right);
}
#endregion#region 知识点三 总结
//归并排序和快速排序都会用到递归
//两者的区别
//相同点:
//1.他们都会用到递归
//2.都会把数组分成几部分
//不同点:
//1.归并排序递归过程中会不停产生新数组用于合并;快速排序不会产生新数组
//2.归并排序是拆分数组完毕后再进行排序;快速排序是边排序边拆分//基本原理
//选取基准
//产生左右标识
//左右比基准
//满足则换位
//排完一次 基准定位
//基准左右递归
//直到有序//套路写法
//基准值变量
//左右游标记录//3层while循环
//游标不停左右移动
//重合则结束
//结束定基准//递归排左右
//错位则结束//注意事项
//左右互放
//while循环外定基准
#endregion

堆排序

在这里插入图片描述

int[] arr = new int[] { 8, 7, 1, 5, 4, 2, 6, 3, 9 };
HeapSort(arr);
for (int i = 0; i < arr.Length; i++)
{Console.WriteLine(arr[i]);
}#region 知识点一 堆排序基本原理
//构建二叉树
//大堆顶调整
//堆顶往后方
//不停变堆顶//关键规则
//最大非叶子节点:
//数组长度/2 - 1//父节点和叶子节点:
//父节点为i 
//左节点2i+1
//右节点2i+2
#endregion#region 知识点二 代码实现
//第一步:实现父节点和左右节点比较
/// <summary>
/// 
/// </summary>
/// <param name="array">需要排序的数组</param>
/// <param name="nowIndex">当前作为根节点的索引</param>
/// <param name="arrayLength">哪些位置没有确定</param>
static void HeapCompare(int[] array, int nowIndex, int arrayLength)
{//通过传入的索引 得到它对应的左右叶子节点的索引//可能算出来的会溢出数组的索引 我们一会再判断int left = 2 * nowIndex + 1;int right = 2 * nowIndex + 2;//用于记录较大数的索引int biggerIndex = nowIndex;//先比左 再比右//不能溢出 if (left < arrayLength && array[left] > array[biggerIndex]){//认为目前最大的是左节点 记录索引biggerIndex = left;}//比较右节点if (right < arrayLength && array[right] > array[biggerIndex]){biggerIndex = right;}//如果比较过后 发现最大索引发生变化了 那就以为这要换位置了if (biggerIndex != nowIndex){int temp = array[nowIndex];array[nowIndex] = array[biggerIndex];array[biggerIndex] = temp;//通过递归 看是否影响了叶子节点他们的三角关系HeapCompare(array, biggerIndex, arrayLength);}
}//第二步:构建大堆顶
static void BuildBigHeap(int[] array)
{//从最大的非叶子节点索引 开始 不停的往前 去构建大堆顶for (int i = array.Length / 2 - 1; i >= 0; i--){HeapCompare(array, i, array.Length);}
}//第三步:结合大堆顶和节点比较 实现堆排序 把堆顶不停往后移动
static void HeapSort(int[] array)
{//构建大堆顶BuildBigHeap(array);//执行过后//最大的数肯定就在最上层//往屁股后面放 得到 屁股后面最后一个索引for (int i = array.Length - 1; i > 0; i--){//直接把 堆顶端的数 放到最后一个位置即可int temp = array[0];array[0] = array[i];array[i] = temp;//重新进行大堆顶调整HeapCompare(array, 0, i);}
}
#endregion#region 知识点三 总结
//基本原理
//构建二叉树
//大堆顶调整
//堆顶往后方
//不停变堆顶//套路写法
//3个函数
//1个堆顶比较
//1个构建大堆顶
//1个堆排序//重要规则
//最大非叶子节点索引:
//数组长度/2 - 1//父节点和叶子节点索引:
//父节点为i 
//左节点2i+1
//右节点2i-1//注意:
//堆是一类特殊的树
//堆的通用特点就是父节点会大于或小于所有子节点
//我们并没有真正的把数组变成堆
//只是利用了堆的特点来解决排序问题
#endregion

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

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

相关文章

git使用流程与规范

原文网址&#xff1a;git代码提交流程与规范-CSDN博客 简介 本文git提交流程与规范是宝贵靠谱的经验&#xff0c;它能解决如下问题&#xff1a; 分支差距过大&#xff0c;导致合代码无数的冲突合完代码后发现代码丢失分支不清晰&#xff0c;无法追溯问题合代码耗时很长&…

数据结构的快速排序(c语言版)

一.快速排序的概念 1.快排的基本概念 快速排序是一种常用的排序算法,它是基于分治策略的一种高效排序算法。它的基本思想如下: 从数列中挑出一个元素作为基准(pivot)。将所有小于基准值的元素放在基准前面,所有大于基准值的元素放在基准后面。这个过程称为分区(partition)操作…

Redis 和 Mysql 如何保证两者数据一致性

文章目录 概述解决方案消息队列异步重试 基于 RocketMQ 的可靠性消息通信&#xff0c;来实现最终一致Canal 组件&#xff0c;监控 Mysql 中 binlog 的日志&#xff0c;把更新后的数据同步到 Redis 里面延时双删弱一致性和强一致性Canal详解 概述 在分布式系统中&#xff0c;保…

失之毫厘差之千里之load和loads

起源 最近在读pandas库的一些文档的时候&#xff0c;顺便也会将文档上的一些demo在编辑器中进行运行测试&#xff0c;其中在读到pandas处理Json数据这一节的时候&#xff0c;我还是像往常一样&#xff0c;将文档提供的demo写一遍&#xff0c;结果在运行的时候&#xff0c;直接…

【React篇】组件错误边界处理(组件错误引起的页面白屏)

我们知道在生产环境react错误会导致整个页面崩溃&#xff0c;显示为空白页面。 比如下图的错误&#xff0c;导致了左侧页面直接白屏&#xff1a; 由于某一个组件报错导致整个页面崩溃是很严重的问题&#xff0c;那么我们应该如何去降低代码报错带来的影响呢&#xff1f; 我们…

用HAL库改写江科大的stm32入门-6-3 PWM驱动LED呼吸灯

接线图&#xff1a; 2 :实验目的&#xff1a; 利用pwm实现呼吸灯。 关键PWM定时器设置&#xff1a; 代码部分&#xff1a; int main(void) {/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*…

【再探】设计模式—访问者模式、策略模式及状态模式

访问者模式是用于访问复杂数据结构的元素&#xff0c;对不同的元素执行不同的操作。策略模式是对于具有多种实现的算法&#xff0c;在运行过程中可动态选择使用哪种具体的实现。状态模式是用于具有不同状态的对象&#xff0c;状态之间可以转换&#xff0c;且不同状态下对象的行…

使用shell命令开启隧道转发的方式

1.适用场景 中转电脑可以通公网&#xff0c;也可以通内网&#xff0c;想把内网映射出去&#xff0c;公网其他电脑就可以通过该隧道远程访问内网的情况 2.命令 开隧道&#xff08;21235是自定义的转发端口&#xff09;&#xff1a; ssh -R 21235:内网地址:ssh端口 用户名公网服…

【C语言】基于C语言实现的贪吃蛇游戏

【C语言】基于C语言实现的贪吃蛇游戏 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C语言学习之路 文章目录 【C语言】基于C语言实现的贪吃蛇游戏前言一.最终实现效果一.Win32 API介绍1.1Win32 API1.2控制台程序1.3控制台屏幕上的坐标COORD…

编程学习 (C规划) 6 {24_4_18} 七 ( 简单扫雷游戏)

首先我们要清楚扫雷大概是如何实现的&#xff1a; 1.布置雷 2.扫雷&#xff08;排查雷&#xff09; &#xff08;1&#xff09;如果这个位置是雷就炸了&#xff0c;游戏结束 &#xff08;2&#xff09;如果不是雷&#xff0c;就告诉周围有几个雷 3.把所有不是雷的位置都找…

蓝桥杯单片机第五届国赛题目

前言&#xff1a;针对串口的练手&#xff0c;此处只作代码记录&#xff0c;不进行分析和展示 目录 题目代码底层驱动主程序核心代码 题目 代码 注&#xff1a;EEPROM的五组后丢弃用一个记录次数的变量进行循环即可&#xff0c;我没有写这一部分代码。 底层驱动 IIC unsign…

[深度学习]yolov10+deepsort+pyqt5实现目标追踪

YOLOv10DeepSORTPyQt5实现目标追踪系统 在现代智能监控系统中&#xff0c;目标追踪技术扮演着至关重要的角色。结合YOLOv10&#xff08;一种先进的实时目标检测算法&#xff09;与DeepSORT&#xff08;一种多目标追踪算法&#xff09;&#xff0c;并通过PyQt5构建用户界面&…

java——网络原理初识

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 目录 1.网络通信概念初识1.1 IP地址1.2端口号1.3协议1.3.1协议分层协议分层带来的好处主要有两个方面 1.3.2 TCP/IP五层 (或四层模型)1.3.3 协议的层和层之间是怎么配合工作的 1.网络通信概念初识…

再度“痛失”TOP5的小米手机,能否接好这碗AI“大活水”?

国产手机终端需求持续修复&#xff0c;国产品牌商是最大受益者。 近日&#xff0c;中国信通院发布2024年4月国内手机市场运行分析报告。报告显示&#xff0c;今年4月&#xff0c;国内市场手机出货量同比增长了28.8%。按品牌来看&#xff0c;国产品牌手机4月出货量占同期手机出…

港口利器:ModbusTCP转CAN轻松连接,提升跨运车效率!

BXKJ系列嵌入式通信模块&#xff0c;宛如一把神奇的钥匙&#xff0c;打开了与特定工业网络沟通的神秘之门。这些模块的可互换性&#xff0c;赋予了用户自由连接至任何所需网络的无限可能。它们与众多主流现场总线和工业以太网网络无缝对接&#xff0c;包括但不限于Profibus、De…

JVM哪些区域可能出现内存溢出,哪些地方需要GC?

GC顾名思义也就是垃圾回收&#xff0c;有人的地方就有江湖&#xff0c;那有数据的地方也理应有垃圾回收&#xff0c;所以思考一下&#xff0c;沿着之前提到过的JVM内存分区&#xff0c;堆&#xff0c;栈&#xff0c;程序计数器&#xff0c;方法区 堆、栈、方法区…

信息学奥赛初赛天天练-17-阅读理解-浮点数精准输出与海伦公式的巧妙应用

PDF文档公众号回复关键字:20240531 1 2023 CSP-J 阅读程序1 阅读程序&#xff08;程序输入不超过数组成字符串定义的范围&#xff1a;判断题正确填√&#xff0c;错误填&#xff1b;除特殊说明外&#xff0c;判断题1.5分&#xff0c;选择题3分&#xff0c;共计40分&#xff0…

C51单片机开发--库函数

知不足而奋进 望远山而前行 目录 系列文章目录 文章目录 前言 目标 内容 开发过程回顾 使用库函数点灯 什么是库函数? 面向库函数和面向寄存器开发 使用delay模块延时 总结 前言 在嵌入式系统开发中&#xff0c;使用库函数是提高开发效率、简化编程的重要手段之一…

Codeforces Round 949 (Div. 2) (A~C)

1981A - Turtle and Piggy Are Playing a Game 贪心&#xff0c;每次取x 2&#xff0c;求最大分数 // Problem: B. Turtle and an Infinite Sequence // Contest: Codeforces - Codeforces Round 949 (Div. 2) // URL: https://codeforces.com/contest/1981/problem/B // Me…

使用CS抓取WIN2012明文密码

目录 实验概述&#xff1a; 开始实验&#xff1a; 实验准备&#xff1a; 打开CS&#xff1a; 生成木马控制wind2012&#xff1a; 抓取明文密码&#xff1a; 实验概述&#xff1a; win2012及win10版本是不允许将明文密码储存在内存中的&#xff0c;此时我们…