我对排序算法的理解

排序算法一直是一个很困惑我的问题,早在刚开始接触 数据结构的时候,这个地方就很让我不解。就是那种,总是感觉少了些什么的感觉。一开始,重新来过,认真来学习这一部分,也总是学着学着就把概念记住了。过了一会,让我重新来写这些算法,又变得不会。

我明白我的问题,就是感觉自己懂了,其实,还是不懂。只要逻辑乱一次,就基本oh my gad了。

然后我就看视频,找一些算法的更通俗易懂的一些理解。还是感觉差了些什么。

不过,最后还是找到一些自己的理解方式。

做关于排序的算法题:

首先你要明白它是怎么排序的。以选择排序为例:

 ok,我们知道选择排序就是每一轮寻找一个最小的值。

继续:看这个选择排序的过程,共进行了6轮、每一轮又进行了多少次比较?

这个问题,就是一个嵌套循环的问题:

写出这个循环的嵌套才能进行下一步:口诀就是外层循环表示行,内层循环表示列。我看了很对其它的解释,个人感觉所有嵌套循环,记住这个特点就足够了。

回到这个算法:

  //很明显,外层循环有6轮,那么外层循环的判定就是arr.length-1。这个很简单。
  //表示的范围就是【0~6】
for(int i=0;i<arr.length-1;i++){
   //内层循环表示列。
   for(){
   }
}

重点来了,怎么写内循环的问题!!!

这里一定要学好,因为不同的排序算法,基本上它的内循环都不同。但是它们都会存在一定的规律和共性。

我们在看这个算法。

每一轮都是找最小值。第一轮,从7个元素找;第二轮从6个元素里面找;第三轮就是5个。

那么内循环表示列:就相当于,第一轮7列(7个元素),第二轮6列(除第一个元素之外。)

for(int i=0;i<arr.length-1;i++){
   //内层循环表示列。
   //它的范围就是:0~6(7列)、1~6(除了第一个元素0之外的6列)、2~6(5列)
   for(int j=i;j<arr.length-1;j++){

     }
}

然后,循环嵌套的问题我们就解决了,基本上,选择排序算法我们的问题就解决一半了!

我们再来看不同排序算法间嵌套循环的共性:以插入排序的嵌套循环为例。

你可以自己尝试一下,写出这个循环的嵌套语句:

//6行,就是外循环6次
for(int i=0;i<arr.length-1;i++){
  //内循环,观察这个算法的要求。
  //第一行:从第二列开始和前一个比较。
  //第二行:从第三列和前面两个比较。
  //第三行:就是第四个,和前面三个比较。这里不太好画图,自己画一下图,就是一种滑坡的形状。
  //那么初始条件,我们可以设为i+1。(从第二列开始)。那么判定条件是什么呢?
  //第一次判定只比较一次,第二次判定比较两次,第三次就是比较三次。那就是j>0咯。
  //它的范围就是:1(和0比较)、2~1(和0,1比较)、3~1(和0,1,2比较)
   for(int j=i+1;j>0;j++){

   }
}

 这个算法和选择排序算法的嵌套循环的共性是什么呢?

重点在内循环。

我的理解是:

   在外循环 i表示行数,内循环 j表示列的前提下。那么一定会在内循环的初始条件或判定条件用到i,而且有且只能用到一次。要么i用在初始条件,要么用在判定条件。

比如:看选择排序的算法:
内循环:for(int j=i;j<arr.length-1;j++)
i用在初始条件。

插入排序的算法:
内循环:for(int j=i+1;j>0;j--)
i用在初始条件。

冒泡排序:这个很简单,就是从第一个往后面比较,小的往前,大的往后。
内循环:for(int j=0;j<arr.length-i-i;j++)
i用在判定条件。

上面三个算法的外循环都是一样的。

我之前做这个算法题时,就这样写过:

错误的写法,选择排序:
for(int j=i;j<arr.length-i;j++)

如果是这样写,那么它的范围就是:
0~6(第一轮比较和之前是一样的比较的比较7次)
1~5(这里只比较了5次)
2~4
3~3(到这里就结束了,不会运行。)
造成的问题就是:只有效比较了三行(也不是很有效,只有效比较了第一行)。后面三行就根本不会比较,只打印出来。
而我们需要比较是6行。和i的关系是紧密联系的!
故此:我得出结论,在排序算法或者嵌套循环有关,在内循环里面如果要使用i。那么只能使用一次。

故此:我得出结论,在排序算法或者嵌套循环有关,在内循环里面如果要使用i。那么只能使用一次。
 

欧克,关于循环嵌套的问题就到这。想自己训练一下,可以尝试打印9*9乘法口诀表,或者打印三角形的形状。这些都运用了嵌套循环。

在来看算法问题:

以插入排序的算法为例:

它的核心就是从第二个元素开始往前比较。你要从内存空间的角度去思考。这里没有涉及堆和栈,堆和栈也很重要,不过在面向对象的时候才会学习堆和栈的空间变化。

它的空间变化:只以前四个数为例。

原数据:56 、34、45、12、67、52、4
从算法是赋值的角度变化:
两两比较,小的排前面。在算法角度就是,两个交换了位置。具体变化:56、34、45、12
第一行:34 34 45 12 ~   temp=56
               34 56 45 12 
 第二行:34 45 45 12  ~  temp=56
                34 45 56 12 
 第三行:34 45 12 12  ~temp=56
                34 45 12 56 
                34 12 12 56    temp=45 
                34 12 45 56 
                12 12 45 56    temp=34
                12 34 45 56 

我们第三行的最终比较结果就是12、34、45、56、67、52、4。

那么就可以写算法了:

//外循环6行
for(int i=0;i<arr.length-1;i++){
  //内循环
   for(int j=i+1;j>0;j++){
       if(arr[j] < arr[j-1]){   //看上面的规律,是不是两两比较。然后小的排前面。
          temp = arr[j];
          arr[j-1] = arr[j];
          arr[i] = temp;
      }
   }
  Systemo.out.println(Arrays.toString(arr));  //打印每一行的结果
}

算法的主要问题在哪,主要就是j、j+1或者j-1这样的判断。不知道怎么用,会不会出事。这就是第二个困扰的问题。

这个问题解决了,基本上算法排序就比较容易理解了。

其实,关于j 、j+1这样的用法和嵌套循环也很类似。就是j+1的范围不能超过原来数组的长度。j-1不能小于原来数组的长度。超出了,基本上这个算法就出错了。

建议:打草稿咯,像我上面那个例子一样,去画一下内存的变化。就不会出错。

这里,关于插入排序的算法就很有意思了,它的核心算法从每一轮找最小的值,这个最小的值不能通过两两比较交换位置。(透露一下:通过比较返回索引值。直到找到最小的值所在索引,然后和第一个数进行交换。)

选择排序核心算法:

for(int i=0;i<arr.length-1;i++){
   //内层循环表示列。
   //它的范围就是:0~6(7列)、1~6(除了第一个元素0之外的6列)、2~6(5列)
   index=i;
   for(int j=i;j<arr.length-1;j++){
        if(arr[index] > arr[j+1]){
           index=j+1;       
       }
     }
       temp = arr[index];   //将第一个位置和找到索引最小的元素进行交换
       arr[i] = arr[index];
       arr[index] = temp;
       System.out.println(Arrays.toString(arr));
}

选择排序的算法去画画它的内存变化吧。

之后我会不停添加其它的算法来验证我的理解和猜想。暂时先写到这了。

补充:嵌套循环还有一个条件,在循环用的一个数组的情况下,内循环的范围不能超过外循环,外循环的范围不能超过原数组。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

版本适配好帮手 Android SDK Upgrade Assistant / Android Studio Giraffe新功能

首先是新版本一顿下载↓&#xff1a; Download Android Studio & App Tools - Android Developers 在Tools中找到Android SDK Upgrade Assistant 可以在此直接查看SDK升级相关信息&#xff0c;不用跑到WEB端去查看了。 例如看一下之前经常要对老项目维护的android 12蓝牙…

RAID相关知识

简介 RAID &#xff08; Redundant Array of Independent Disks &#xff09;即独立磁盘冗余阵列&#xff0c;通常简称为磁盘阵列。RAID技术将多个单独的物理硬盘以不同的方式组合成一个逻辑磁盘&#xff0c;从而提高硬盘的读写性能和数据安全性。 数据组织形式 分块&#x…

给定长度值length,把列表切分成每段长度为length的N段列表,Kotlin

给定长度值length&#xff0c;把列表切分成每段长度为length的N段列表&#xff0c;Kotlin import kotlin.random.Randomfun main(args: Array<String>) {var source mutableListOf<String>()val end Random.nextInt(30) 1for (i in 0 until end) {source.add(i.…

ubuntu22.04 DNSSEC(加密DNS服务) configuration

/etx/systemd/resolved.conf是ubuntu下DNS解析服务配置文件&#xff0c;systemd为ubuntu下system and service配置目录 step 1——修改resolved.conf参数 管理员权限打开 /systemd/resolved.conf sudo nano /etc/systemd/resolved.conf修改如下&#xff1a; # This file i…

DAY14_FilterListenerAjaxAxiosJsonfastjson综合案例-axios和html交互

目录 1 Filter1.1 Filter概述1.2 Filter快速入门1.2.1 开发步骤1.2.2 代码演示 1.3 Filter执行流程1.4 Filter拦截路径配置1.5 过滤器链1.5.1 概述1.5.2 代码演示1.5.3 问题 1.6 案例1.6.1 需求1.6.2 分析1.6.3 代码实现1.6.3.1 创建Filter1.6.3.2 编写逻辑代码1.6.3.3 测试并抛…

51单片机定时器/计数器

目录 1、定时器/计数器0/1介绍 1.1 定时器介绍 1.2 单片机定时/计数器原理 2、定时器/计数器0和1的相关寄存器 2.1 定时器/计数器控制寄存器TCON 2.2 定时器/计数器工作模式寄存器TMOD 2.3 定时器/计数器工作模式 2.3.1 模式0(13位定时器/计数器) 2.3.2 模式1(16位定…

SpringBoot运维

能够掌握SpringBoot程序多环境开发 能够基于Linux系统发布SpringBoot工程 能够解决线上灵活配置SpringBoot工程的需求 Windows打包运行 你的电脑不可能一直开着机联网作为服务器&#xff1a; 我们将我们项目打包放到外部的服务器上&#xff0c;这样其他用户才能正常访问&#x…

设计模式之四:工厂模式

引言&#xff1a;除了使用new操作符之外&#xff0c;还有更多制造对象的方法。同时&#xff0c;实例化这个活动不应该总是公开地进行。 1.简单工厂模式 这里有一些相关的具体类&#xff0c;要在运行时有一些具体条件来决定究竟实例化哪个类。这样的代码&#xff08;if..elseif…

MFC自定义控件使用

用VS2005新建一个MFC项目,添加一个Custom Control控件在窗体 我们需要为自定义控件添加一个类。项目,添加类,MFC类 设置类名字,基类为CWnd,你也可以选择CDialog作为基类 类创建完成后,在它的构造函数中注册一个新的自定义窗体,取名为"MyWindowClass" WNDCL…

深入了解HTTP代理在网络爬虫与SEO实践中的角色

随着互联网的不断发展&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;成为各大企业和网站重要的推广手段。然而&#xff0c;传统的SEO方法已经难以应对日益复杂和智能化的搜索引擎算法。在这样的背景下&#xff0c;HTTP代理爬虫作为一种重要的工具&#xff0c;正在逐渐被…

JUC中其他常用类

1.CopyOnWriteArrayList ArrayList是线程不安全的&#xff0c;Vector是线程安全的(方法被Synchronized修饰)&#xff0c;CopyOnWriterArrayList是在Vector的基础上再做优化&#xff0c;因为当读取操作较多时&#xff0c;Vector的效率不高。CopyOnWriterArrayList中读操作并没有…

ceph-mon运行原理分析

一、流程&#xff1a;ceph-deploy部署ceph-mon组建集群 1.ceph-deploy部署ceph-mon的工作流程及首次启动 1&#xff09;通过命令创建ceph-mon&#xff0c;命令为&#xff1a;ceph-deploy create mon keyring def mon(args):if args.subcommand create:mon_create(args)elif…

苍穹外卖day07——缓存菜品套餐+购物车功能实现

缓存菜品——需求设计与分析 问题说明 用户访问量过大带来的一个直接效果就是响应速度慢&#xff0c;使用体验下降。 实现思路 使用redis缓存菜品数据&#xff0c;减少数据库查询操作。 页面展示上基本就是同一个分类在同一页&#xff0c;所以key-value结构可以使用不同的分…

Vue没有node_modules怎么办

npm install 一下 然后再npm run serve 就可以运行了

记一次偶然的网站sql注入

自己学了点渗透的内容后就开始尝试挖漏洞了&#xff0c;偶然发现了这个yp网站&#xff0c;由于好奇心就浏览了一下里面的内容&#xff0c;突然注意到有个id的地方跳转页面&#xff0c;于是就想试试看有没有注入&#xff0c;就有了以下的内容。。。 界面如下 当时就是好奇点进去…

事件标志组

Q: 什么是事件标志组&#xff1f; A: 事件标志位&#xff1a;表明某个事件是否发生&#xff0c;联想&#xff1a;全局变量 flag。通常按位表示&#xff0c;每一个位表示一个事件&#xff08;高8位不算&#xff09; 事件标志组是一组事件标志位的集合&#xff0c; 可以简单的理…

ElasticSearch基础篇-Java API操作

ElasticSearch基础-Java API操作 演示代码 创建连接 POM依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sch…

springCloud Eureka注册中心配置详解

1、创建一个springBoot项目 2、在springBoot项目中添加SpringCloud依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>2021.0.3</version><type>…

从源程序到可执行文件的四个过程

从源程序到可执行文件的四个过程 预处理编译汇编链接 程序要运行起来&#xff0c;必须要经过四个步骤&#xff1a;预处理、编译、汇编和链接&#xff0c;如下图所示&#xff1a; -E选项&#xff1a;提示编译器执行完预处理就停下来&#xff0c;后边的编译、汇编、链接就先不执…

关于在VS2017中编译Qt项目遇到的问题

关于在VS2017中编译Qt项目遇到的问题 【QT】VS打开QT项目运行不成功 error MSB6006 “cmd.exe”已退出,代码为 2。如何在VS2017里部署的Qt Designer上编辑槽函数 【QT】VS打开QT项目运行不成功 error MSB6006 “cmd.exe”已退出,代码为 2。 链接 如何在VS2017里部署的Qt Design…