1.常见8种排序算法分析笔记之-空间O(1)三种(冒泡、选择、插入)

2023-05-16

文章目录

  • 空间复杂度为O(1)的三种排序法
    • 一、冒泡排序法
      • 1.代码实现思想
      • 2.复杂度分析
      • 3.代码实现
      • 4.代码测试
    • 二、选择排序法
      • 1.代码实现思想
      • 2.复杂度分析
      • 3.代码实现
      • 4.代码测试
    • 三、插入排序法
      • 1.代码实现思想
      • 2.复杂度分析
      • 3.代码实现
      • 4.代码测试

空间复杂度为O(1)的三种排序法

一、冒泡排序法

1.代码实现思想

​ 参考文章

慕课网数据结构与算法课程
  • 冒泡,即大的数据下层,小的数据上浮。

  • 代码实现:每一轮,指定数组中的一个位置,放置该位置前所有元素中的最大值,即通过数据两两比较获取

  • 要将N-1个位置放置好数据,需要N-1轮

  • 每轮,指针j从0位置依次遍历,遍历到指定位置的前一个位置,比较当前位置j与下个位置j+1位置数值大小,是否交换

  • 代码优化对于大量有序的数列,可能要指定的位置已经排好序,无需再循环判断,即,为了减少循环,用变量lastSwap记录已经排号序的位置,下次循环指定的位置是标志位前一个无序位置

2.复杂度分析

  • 时间复杂度: O ( N 2 ) O(N^2) O(N2),即需要 O ( N ) O(N) O(N)轮,每轮 O ( N ) O(N) O(N)的操作

  • 空间复杂度: O ( 1 ) O(1) O(1),即需要常数级的变量空间,无需开辟新的空间

  • 稳定性:指的是相同元素保存相对位置不变的特性,可以设计成稳定排序,即相等元素比较时不交换

3.代码实现

public class BubbleSort {
	private BubbleSort() {}
	
	public static <E extends Comparable<E>> void sort(E[] arr) {
		// 先处理特殊情况
		if(arr == null || arr.length <= 2)  return;
		
		for(int i = arr.length -1; i > 0;) { // 指定要处理的位置,N-1轮,后面数先排好序
            int lastSwap = 0;		// 从后往前看,标记已经排好序的最后的位置
		  	for(int j = 0; j < i; j ++) { // 遍历比较,注意循环终止条件j + 1 <= i
				if(arr[j].compareTo(arr[j + 1]) > 0) { // 注意数组越界
					swap(arr, j, j + 1);
                   	  lastSwap = j + 1;	
				}
			}
            i = lastSwap - 1;	// i 不是每次减一,而是直接跳到标记没有排好序的最后一个位置,减少循环
		}
	}

	private static <E> void swap(E[] arr, int j, int i) {
		E t = arr[j];
		arr[j] = arr[i];
		arr[i] = t;	
	}
    
    // 代码测试
    public static void main(String[] args) {
		int n = 10000;
		Integer[] arr = ArrayGenerator.generateRandomArray(n, n);
		SortingHelper.sortTime("BubbleSort", arr);
	}
}

4.代码测试

设计两个辅助测试类:

  • 数组生成器(ArrayGenerator.class):提供两个接口,生成有序数组和无序数组

    • 有序数组,传入数组大小,按照数组索引依次遍历填入有序数值
    • 无序数组,借助JAVA自带Random类,传入数组大小和Random边界,将边界内随机生成的数值填入数组
  • 排序算法校验和性能测试器(SortingHelper.class),提供两个接口,排序校验,性能时间打印

    • 排序校验,默认是从小到大,两两比较判断是否有没有排序好的情况
    • 性能测试,传入排序算法名,可以扩展为多个排序算法调用,打印测试时间前进行排序校验
  • 代码实现:

import java.util.Random;

public class ArrayGenerator {
	private ArrayGenerator() {}
	
	// 正序排列的数组
	public static Integer[] generateOrderedArray(int n) {
		Integer[] arr = new Integer[n];
		for(int i = 0; i < n; i++) {
			arr[i] = i;
		}
		return arr;
	}

	// 乱序排列的数组
	public static Integer[] generateRandomArray(int n, int border) {
		Integer[] arr = new Integer[n];
		Random rdm = new Random();
		for(int i = 0; i < n ; i++) {
			arr[i] = rdm.nextInt(border);
		}
		return arr;
	}
}
public class SortingHelper {
	private SortingHelper() {}
	
	public static <E extends Comparable<E>> boolean isSorted(E[] arr) {
		for(int i = 1; i < arr.length; i++) {
			if(arr[i-1].compareTo(arr[i]) > 0) {
				return false;
			}
		}
		return true;
	}
	
	public static <E extends Comparable<E>> void sortTime(String sortName, E[] arr) {
		long startTime = System.nanoTime();
		
		if(sortName.equals("BubbleSort")) {
			BubbleSort.sort(arr);
		} else if(sortName.equals("InsertionSort")) {
			InsertionSort.sort(arr);
		} else if(sortName.equals("SelectionSort")) {
			SelectionSort.sort(arr);
		} else if(sortName.equals("MergeSort")) {
			MergeSort.sort(arr);
		}
		long lastTime = System.nanoTime();
		double time = (lastTime - startTime) / 1000000000.0;
		
		if(!SortingHelper.isSorted(arr)) {
			throw new RuntimeException("Sort false!");
		}		
	
		System.out.println(String.format(
				"%s, n = %d : %f s", sortName, arr.length, time));
	}
}
输出结果:
BubbleSort, n = 10000 : 0.417135 s
选择排序法

二、选择排序法

1.代码实现思想

  • 与冒泡思想类似,每轮选择最小元素(最大元素)放在指定位置,一般从左往右依次放置
  • 选择过程也是比较交换过程,为了减少交换操作,设计一个变量minIndex储存当前轮最小值索引,遍历比较
  • 最后将minIndex指向的数值与指定位置的数值进行交换,得到指定位置应该放的最小元素

在这里插入图片描述

2.复杂度分析

  • 时间复杂度: O ( N 2 ) O(N^2) O(N2),即需要 O ( N ) O(N) O(N)轮,每轮 O ( N ) O(N) O(N)的操作

  • 空间复杂度: O ( 1 ) O(1) O(1),即需要常数级的变量空间,无需开辟新的空间

  • 稳定性:指的是相同元素保存相对位置不变的特性,正常算法无法保持稳定性,因为交换后会打乱顺序

3.代码实现

public class SelectionSort {
	private SelectionSort() {}
	
	public static <E extends Comparable<E>> void sort2(E[] arr) {
		if(arr == null || arr.length < 2) return;
		
		for(int i = 0; i < arr.length - 1; i ++) { // 最后一个元素自动确认,减少循环次数
			int minIndex = i; // 目标要放置位置的元素 = minIndex = i
			for(int j = i + 1; j < arr.length; j ++) {
				minIndex = arr[j].compareTo(arr[minIndex]) < 0 ? j : minIndex;
			}
			swap(arr, minIndex, i);
		}
	}
	
	private static <E>void swap(E[] arr, int j, int i) {
		E t = arr[j];
		arr[j] = arr[i];
		arr[i] = t;
	}
}

4.代码测试

public static void main(String[] args) {
		int n = 10000;
		System.out.println("Random Array:");
		Integer[] arr = ArrayGenerator.generateRandomArray(n, n);
		Integer[] arr1 = Arrays.copyOf(arr, arr.length);
		
		SortingHelper.sortTime("BubbleSort", arr);
		SortingHelper.sortTime("SelectionSort", arr1); // 无序选择最好,减少交换次数
	}
Random Array:
BubbleSort, n = 10000 : 0.410318 s
SelectionSort, n = 10000 : 0.058414 s
  • 通过测试知,选择排序法实现正确,且时间性能方面,由于减少了交换次数,会相对比冒泡排序法更好。
插入排序法

三、插入排序法

1.代码实现思想

  • 每一轮,对指定元素,找到它要插入的位置,保证插入位置之前的元素已经排好序

  • 通过两两比较的方式判断插入位置,保证插入的位置前所有元素比指定元素小,后所有元素比指定元素大

  • 减少比较次数先找位置,不急着交换,只是将非插入位置元素往后挪,复杂度会低些,找到位置后,再将指定元素放到插入位置上

2.复杂度分析

  • 时间复杂度: O ( N 2 ) O(N^2) O(N2),即需要 O ( N ) O(N) O(N)轮,每轮 O ( N ) O(N) O(N)的操作
    • 有序数组的排序, O ( 1 ) O(1) O(1),需要比较n-1次,无需交换元素
  • 空间复杂度: O ( 1 ) O(1) O(1),即需要常数级的变量空间,无需开辟新的空间
  • 稳定性:指的是相同元素保存相对位置不变的特性,因为位置是相对挪动,保证相同元素不挪动,可以保证稳定性

3.代码实现

import java.util.Arrays;

import bubbleSort.ArrayGenerator;
import bubbleSort.SortingHelper;

public class InsertionSort {
	private InsertionSort() {};
	
	public static <E extends Comparable<E>> void sort(E[] arr) {
		// 精髓是两两比较,如果已经排好序,就不再交换,与冒泡比较,减少交换
		// 找到要处理的数要插到的位置,该位置后的元素依次挪位,该位置前的元素已经排好序
		for(int i = 1; i < arr.length; i ++) {
			E target = arr[i]; // 要处理的目标元素
			int j;
			for(j = i; j > 0 && arr[j - 1].compareTo(target) > 0; j --) {
				arr[j] = arr[j - 1];
			}
			arr[j] = target;
		}
	}
}

4.代码测试

public static void main(String[] args) {
		int n = 10000;
    	// 无序数组的测试
		System.out.println("Random Array:");
		Integer[] arr = ArrayGenerator.generateRandomArray(n, n);
		Integer[] arr1 = Arrays.copyOf(arr, arr.length);
		Integer[] arr2 = Arrays.copyOf(arr, arr.length);
		
		SortingHelper.sortTime("BubbleSort", arr);
		SortingHelper.sortTime("SelectionSort", arr1); // 无序选择最好,减少交换次数
		SortingHelper.sortTime("InsertionSort", arr2);
		System.out.println();
		
    	// 有序数组的测试
		System.out.println("Order Array:");
		arr = ArrayGenerator.generateOrderedArray(n);
		arr1 = Arrays.copyOf(arr, arr.length);
		arr2 = Arrays.copyOf(arr, arr.length);
		SortingHelper.sortTime("BubbleSort", arr);
		SortingHelper.sortTime("SelectionSort", arr1);
		SortingHelper.sortTime("InsertionSort", arr2); // 有序,插入最好,已经排好序的无序操作
	}
Random Array:
BubbleSort, n = 10000 : 0.430529 s
SelectionSort, n = 10000 : 0.057633 s
InsertionSort, n = 10000 : 0.153631 s

Order Array:
BubbleSort, n = 10000 : 0.106295 s
SelectionSort, n = 10000 : 0.046629 s
InsertionSort, n = 10000 : 0.000241 s
  • 测试结果显示:排序算法正确,无序数组,性能方面,选择排序法由于交换次数较少,较其他两种较优
    • 有序数组插入排序法,对已经排好序的数组操作较简单,性能较其他两种较优
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

1.常见8种排序算法分析笔记之-空间O(1)三种(冒泡、选择、插入) 的相关文章

  • 【BUG解决】使用body-parser失效的实例解决

    前言 最近在使用express框架写Node代码 xff0c 遇到一个问题使用body parser模块失效 整整困在这里一天时间 xff01 xff01 xff01 res send req body 返回结果一直为空 但是代码的书写又看
  • BOCHS问题总结篇

    在官网上下载的bochs 2 4 5 win32版 bochs启动时会读bochsrc bxrc里的配置 xff0c 而bochsrc sample txt则是个sample xff0c 可以在这个sample里阅读相关参数的设置 1 RO
  • 关于Access的左连接

    这篇随笔没有什么深奥的技术要讨论 xff0c 只是自己一个知识上的盲点 xff1a 不知道在Access中如何进行左连接的操作 通过在网上搜索 xff0c 最后在CSDN上找到了自己要的答案 xff0c 因此觉得有必要记录下来 xff1a
  • ubuntu下安装Calibre

    Calibre是电子书管理软件 xff0c 支持Amazon Apple Bookeen Ectaco Endless Ideas Google HTC Hanlin Song设备及格式 xff0c 功能十分强大 ubuntu 有很多包都可
  • 编译Linux内核数

    本文是参考了网上多篇帖子而写的算不上什么原创 唯一值得欣慰的只不过在本机上实现罢了 因为毕竟失败了几次 也因为本人是初学驱动编程 很多简单的问题在我来说是相当的困难的 望有识之士不要笑话 最后 xff0c 希望本文能给刚学驱动而还没开头的人
  • 构造内核源码树

    编写驱动程序时 xff0c 需要内核源码树的支持 内核源码树时从内核源代码编译得到的 下面开始构造内核源代码的步骤 以Ubuntu为例子 1 下载内源代码 xff0c 位置www kernel org 注意 xff1a 源码树内核的版本要和
  • 裁剪图像中感兴趣区域python

    题外话 xff1a 比较全面的缩略图及相应源码 http matplotlib org gallery html http www cnblogs com wei li archive 2012 05 23 2506940 html 题外外
  • Linux设备驱动程序(LDD)中snull的编译问题

    对LDD中snull程序 xff0c 编译的时候会有许多问题 xff0c 鉴于网上还没有合适的解决办法 xff0c 做此总结 xff0c 整理知识 本文在debian6 0上运行通过 xff0c 内核版本为2 6 32 学习LDD中网络驱动
  • 认识(大端--小端)端模式

    span style color 000000 端模式 xff08 Endian xff09 的这个词出自Jonathan Swift书写的 格列佛游记 这本书根据将鸡蛋敲开的方法不同将所有的人分为两类 xff0c 从圆头开始将鸡蛋敲开的人
  • HOW TO install nam for ns2 on debian

    Debian is convinent to install software packages for the tool aptl Like many other packages we can use apt get install n
  • c++ #pragma once和 #ifndef 优缺点对比分析

    pragma once ifndef方式为了避免同一个头文件被包含 xff08 include xff09 多次 pragma once 声明 定义语句 ifndef SOMEFILE H define SOMEFILE H 声明 定义语句
  • roslaunch找不到packge

    roslaunch找不到packge 尝试下面几种做法 1 source bashrc 2 source catkin ws devel setup bash 3 rospack profile 为确保ROS能找到新包 xff0c 常常在发
  • DSP:TMS320C6657 之 UART波特率问题

    6657 设置串口波特率 以614400为例 xff08 1 xff09 根据公式计算分频系数 xff08 2 xff09 1GHz 主频下 UART 输入频率 166666666Hz xff08 1 6 xff09 xff08 3 xff
  • 手写httpServer Demo案例

    相信每一个java程序猿在学习javaWeb的时候 xff0c 或多或少接触了Servlet 或者说通过Servlet来完成页面发送的请求 今天 xff0c 模仿Servlet接受和处理请求实现一个简单的httpServer 该Server
  • ubuntu18.04 查看在用串口

    1 终端输入cutecom 打开串口助手 xff0c 可能没有下载 xff0c 可根据提示下载安装 sudo cutecom 2 点击device旁边的下拉按钮即可查询当前在用的串口
  • Linux解决未定义的引用过程记录

    Linux解决未定义的引用过程记录 在摸索vscode使用的过程中 xff0c 编写的代码出现了为定义的引用错误 csdn上搜索了很多 xff0c 代码小白看完觉得写的非常的简略 xff0c 完全无从下手 xff08 应该是我太菜了 xff
  • 十一种室内定位传感器方案汇总介绍与对比(机器人、物联网领域)

    室内定位传感器方案汇总 目录 室内定位传感器方案汇总 1 定位方案概述 1 1 内定位系统有最基本的5种算法 xff1a 1 2 常用的室内定位技术主要包括以下几种 xff1a 1 3 定位理论 1 4 不同的定位方案对比 2 各种定位方案
  • C++中的unique函数

    STL中的unique函数的头文件 xff1a span class hljs preprocessor include lt iostream gt span unique 的作用是 去掉 容器中相邻元素的重复元素 xff0c 这里所说的
  • 单片机开发入门---从零开始玩转FRDM-KL25Z

    一 背景介绍 最近需要开发一个程序 xff0c 使用飞思卡尔的开发板FRDM KL25Z xff0c 来设计一款 西蒙游戏 的改进版 xff0c 下面我们先来了解一下西蒙游戏 西蒙游戏 是一款益智休闲类小游戏 xff0c 它的游戏规则是 x
  • SSD---系统架构

    SSD主要由两大模块构成 主控和闪存介质 另外可选的还有Cache缓存单元 主控是SSD的大脑 xff0c 承担着指挥 运算和协调的作用 xff0c 具体表现在 xff1a 前端实现标准主机接口与主机通信 xff0c 接口包括SATA SA

随机推荐

  • SSD核心技术---FTL

    FTL算法的优劣与否 xff0c 直接决定了SSD在性能 xff08 Performance xff09 可靠性 xff08 Reliability xff09 耐用性 xff08 Endurance xff09 等方面的好坏 xff0c
  • SSD---PCIe介绍

    SSD已经大跨步迈入PCIe时代 作为SSD的一项重要技术 xff0c 我们有必要对PCIe有个基本的了解
  • SSD---NVMe介绍

    何为NVMe xff1f NVMe即Non Volatile Memory Express xff0c 是非易失性存储器标准 xff0c 是跑在PCIe接口上的协议标准 NVMe的设计之初就有充分利用了PCIe SSD的低延时以及并行性 x
  • SSD---ECC原理

    我们知道 xff0c 所有型号的闪存都无法保证存储的数据会永久稳定 xff0c 这时候就需要ECC xff08 纠错码 xff09 去给闪存纠错 ECC能力的强弱直接影响到SSD的使用寿命和可靠性 本章将简单介绍ECC的基本原理和目前最主流
  • 音响发烧友---HiFi音频功放

    最近一直想做个开源的电子项目 xff0c 思考许久还是选择做个HiFi音频功放 作为一个音响发烧友 xff0c 带大家DIY一台属于自己的功放 聆听一下 xff0c 纯正的音乐之美 首选需要了解一下功放的类型 xff1a 纯甲类功率放大器乙
  • Altium Designer20常用使用快捷键

    一 AD20常用快捷键 PCB布线常使用 xff1a ctrl 43 m 测量长度 Q 单位切换 shift 43 ctrl 43 r 取消显示标注 shift 43 S 显示层切换 ctrl 43 右击 高亮显示一条线 ctrl 43 D
  • Altium Designer20 交叉选择模式

    在使用Altium Designer进行PCB布局时 xff0c 首先我们需要将原理图元器件更新到PCB中 xff0c 所有的元件封装都会汇集到PCB中 xff0c 但并没有根据电路模块进行分类聚集 xff1b 我们可以使用AD的交叉选择模
  • Altium Designer20 批量修改元件丝印大小和位置

    在进行PCB布线时 xff0c 我们经常需要调整元件丝印的大小和位置 有了丝印才能在PCB焊接和调试板子的时候得心应手 xff0c 下面介绍一种便捷的方法 xff0c 来实现批量修改元件丝印和位置 1 修改元件丝印大小 xff08 1 xf
  • 图像重叠区域

    http www cnblogs com dwdxdy archive 2013 08 02 3232331 html
  • bat批处理---实现输入指定拷贝文件

    在windows平台下 xff0c 平常的给芯片下载程序过程中 xff0c 经常遇到需要在多个文件夹下面拷贝bin文件的情况 xff0c 为了实现能够通过输入参数 xff0c 来选择需要拷贝的问下 xff0c 写了一个 bat批处理文件 只
  • Altium Designer20 PCB规则设置

    我们在进行PCB布线之前 xff0c 需要对PCB布线进行规则设置 xff0c 如果大家只是DIY爱好者 xff0c 那我们将设置价格最经济的PCB规则 xff0c 我们可以以捷配官网的PCB工艺信息作为参考 xff1b 下面我将介绍常用的
  • 入门到放弃之 NVMe-MI --- 协议简介

    在学习NVMe MI协议之前 xff0c 感觉协议是如此的枯燥 xff0c 通过短时间的阅读Spec发现协议规范定义的精妙绝伦 xff1b 协议中各种细节处理的相当到位 xff0c 最有趣的是消息服务模型的状态机设计 xff0c 希望大家一
  • NVMe-MI --- Message Transport(消息传输)

    3 消息传输 该规范定义了一个支持多种消息传输的接口 消息格式与带外机制和带内隧道机制相同 3 1 NVMe MI消息 NVMe MI消息在带外机制和带内隧道机制中都有使用 NVMe MI消息的格式如图17和图18所示 在带外机制中 xff
  • NVMe-MI --- Message Servicing Model(消息服务模型)

    4 消息服务模型 4 1 NVMe MI 消息 图23展示了NVMe MI消息的分类 NVMe MI消息的两个主要类别是请求消息和响应消息 当使用带外机制时 xff0c 请求消息由管理控制器发送到管理端点 在使用带内隧道机制时 xff0c
  • NVMe-MI --- Management Interface Command Set

    Management Interface Command Set 命令集定义了当NMIMT值被设置为NVMe MI命令时 xff0c 请求者可以提交的命令信息 管理接口命令集同时适用于带外机制和带内隧道机制 NVMe MI消息结构以及所有N
  • PCIe总线引脚定义

    然后看一下PCI E的接口定义 这就是显卡插口前面的那段短的金手指 xff0c 就是这段 xff1a 这一段负责供电 SMBus和感知设备是否插上 xff0c 对于数据的传输作用不大 xff0c 所以不用深究 用浅绿色标出来的是检测插槽上设
  • Mbus新增主动报警功能,简单问题的波折路程。

    由于用到了主动报警上传功能 一个简单的if判断 xff0c 便实现了判断与上传功能 脱机测试 xff0c 上流量台测试 xff0c 都正常 以为这件事便了了 结果到了现场却给暴出了问题 xff0c 没法收到报警 于是 xff0c 一对一的现
  • 相机IMU联合标定

    单目相机内参标定 xff1a xff08 焦距 xff0c 光心 https blog csdn net qq 42399848 article details 89298212 ops request misc 61 257B 2522r
  • Hough变换理解

    reference http blog csdn net app 12062011 article details 11307053 一 简单介绍 Hough变换是图像处理中从图像识别几何形状的基本方法之一 xff0c 霍夫变换寻找直线和圆
  • 1.常见8种排序算法分析笔记之-空间O(1)三种(冒泡、选择、插入)

    文章目录 空间复杂度为O 1 的三种排序法一 冒泡排序法1 代码实现思想2 复杂度分析3 代码实现4 代码测试 二 选择排序法1 代码实现思想2 复杂度分析3 代码实现4 代码测试 三 插入排序法1 代码实现思想2 复杂度分析3 代码实现4