算法-排序详解

news2025/1/14 18:13:51

目录

前言

比较排序

选择排序

插入排序

冒泡排序

归并排序

快速排序

非比较类排序

计数排序

桶排序

基数排序

排序的稳定性

排序算法的题目


前言

计算机的工作之一就是对数据的处理,处理数据有一个常见的操作就是对数据排序,比如新闻系统总是按时间把最新的新闻推荐给我们,比如说以前我们讲到的二分查找,他也是基于数据的有序性。在这里我将详细讲解排序算法,下面是对排序算法的总结。

比较排序

选择排序

每次循环都从未排序数据中找到最小值,放到已排序序列的末尾,时间复杂度是O(N2)

func search(num []int) []int {
  len_num := len(num)
  copy_nums := make([]int, len_num)
  copy(copy_nums, num)
  for i := 0; i < len_num; i++ {
    minindex := i
    for j := i + 1; j < len_num; j++ {
      if copy_nums[minindex] > copy_nums[j] {
        minindex = j
      }
    }
    copy_nums[i], copy_nums[minindex] = copy_nums[minindex], copy_nums[i]
  }
  return copy_nums
}
插入排序

从前到后依次考虑每个未排序数据,在已排序序列中找到合适位置插入. 时间复杂度是O(N2)

func search(num []int) []int {
    len_num := len(num)
    copy_nums := make([]int, len_num)
    copy(copy_nums, num)
    for i := 1; i < len_num; i++ {
       for j := i; j > 0; j-- {
          if copy_nums[j] < copy_nums[j-1] {
             copy_nums[j], copy_nums[j-1] = copy_nums[j-1], copy_nums[j]
          }
       }
    }
    return copy_nums
}

我们在来看一个优化版本,这个不是最优的,每次发现满足条件的,都会进行一次交换。那我们能不能想到,找到最终满足条件的在交换了,那么我们就有一个优化版本。

func search(num []int) []int {
  len_num := len(num)
  copy_nums := make([]int, len_num)
  copy(copy_nums, num)
  for i := 1; i < len_num; i++ {
    temp := copy_nums[i]
    var j int
    for j = i; j > 0 && copy_nums[j-1] > temp; j-- {
      copy_nums[j] = copy_nums[j-1]
    }
    copy_nums[j] = temp
​
  }
  return copy_nums
}

这个效率高些,不用频繁的交换,选择排序在某些情况下,比如说数据近似有序以及数据规模小的情况下,甚至比快排还要高效。

冒泡排序

不断循环扫描,每次查看相邻的元素, 时间复杂度是O(N2)

func search(num []int) []int {
  len_num := len(num)
  copy_nums := make([]int, len_num)
  copy(copy_nums, num)
  for i := 0; i < len_num; i++ {
    for j := 0; j < len_num-1; j++ {
      if copy_nums[j] > copy_nums[j+1] {
        copy_nums[j], copy_nums[j+1] = copy_nums[j+1], copy_nums[j]
      }
    }
​
  }
  return copy_nums
}

以上三种排序时间复杂度都是O(N2),选择排序是每次选择最小的一个,冒泡排序外层表示循环次数,两个数据的比较

归并排序

归并排序是一种基于分治的算法,时间复杂度是O(NlogN),也就分成两部分,分开排序,再合并, 时间复杂度是O(nlogn)

func search(num []int, l, r int) {
  if l >= r {
    return
  }
  mid := (l + r) >> 1
  search(num, l, mid)
  search(num, mid+1, r)
  merge_sort(num, l, mid, r)
}
​
func merge_sort(num []int, l, mid, r int) {
  temp := []int{}
  //这个是分治的数组然后去比较,然后替换原始数据,就替换完成了
  for i := l; i <= r; i++ {
    temp = append(temp, num[i])
  }
  i, j := l, mid+1
  for k := l; k <= r; k++ {
    if i > mid {
      num[k] = temp[j-l]
      j++
    } else if j > r {
      num[k] = temp[i-l]
      i++
    } else if temp[i-l] >= temp[j-l] {
      num[k] = temp[j-l]
      j++
    } else if temp[i-l] < temp[j-l] {
      num[k] = temp[i-l]
      i++
    }
  }
​
}
​
func main() {
  num := []int{}
  for i := 0; i < 10; i++ {
    num = append(num, rand.Intn(30))
  }
  search(num, 0, len(num)-1)
  fmt.Println(num)
}
快速排序

在这里我将写的是三路快排,也就是说左边部分是比基准数据小,中间部分是和基准数据一样大,右边部分是比基准数据大。那么中间部分就不用排序了,左右两边在分别排序,这样也就减少了,数据比较规模. 时间复杂度是O(nlogn)

func quickSort(num []int, l, r int) {
  if l >= r {
    return
  }
  v := num[l]
  lt := l     //[l,lt)
  gt := r + 1 // [gt,r]
  //中间与v相等的数据是 [lt,gt),这部分数据是不用比较
  i := l + 1
  for i < gt {
    if v > num[i] {
      num[lt+1], num[i] = num[i], num[lt+1]
      i++
      lt++
    } else if v < num[i] {
      num[gt-1], num[i] = num[i], num[gt-1]
      gt--
    } else {
      i++
    }
  }
  num[lt], num[l] = num[l], num[lt]
  quickSort(num, l, lt-1)
  quickSort(num, gt, r)
}

非比较类排序

计数排序

计数排序要求输入的数据必须是有确定范围的整数。将输入的数据作为key 存储在额外的数组中,然后依次把计数大于1的填充会原数组

时间复杂度是O(N+M) ,N 为元素个数,M为数值范围

桶排序

桶排序假设输入数据服从均衡分布,将数据分到有限的数据的桶里,应先根据数据的规模确定桶的数量,在把数据放到桶里比如可以通过取模的方式,每个桶先分别排序,把排好序的桶的数据合并在排序

时间复杂度O(N) ~ O(N^2)

基数排序

基数排序把数据切割成一位位数字(0-9),从低位到高位对每一位分别进行计数排序

时间复杂度是O(NK),k 为数字位数

排序的稳定性

什么是排序算法的稳定性呢,如果排序前后它们的相对次序一定保持不变,就称排序算法是稳定的否则就称排序算法是不稳定的

稳定的排序算法:插入、冒泡、归并、计数、桶

不稳定的排序:选择、希尔、快速、堆排序

如果大家想检测自己的排序算法是否正确可以看leadcode 912

排序算法的题目

leadcode 1122

给你两个数组,arr1arr2arr2 中的元素各不相同,arr2 中的每个元素都出现在 arr1 中。

arr1 中的元素进行排序,使 arr1 中项的相对顺序和 arr2 中的相对顺序相同。未在 arr2 中出现过的元素需要按照升序放在 arr1 的末尾。

示例 1:

输入:arr1 = [2,3,1,3,2,4,6,7,9,2,19], arr2 = [2,1,4,3,9,6]
输出:[2,2,2,1,4,3,3,9,6,7,19]

比较排序 时间复杂度是O(nlogn)

func relativeSortArray(arr1 []int, arr2 []int) []int {
  arr2_map := map[int]int{}
  for i, v := range arr2 {
    arr2_map[v] = i
  }
  sort.Slice(arr1, func(i, j int) bool {
    n1, n2 := 0,0
    var ok bool
    if n1, ok = arr2_map[arr1[i]]; !ok {
      n1 = len(arr2)
    }
    if n2,ok = arr2_map[arr1[j]];!ok{
      n2 = len(arr2)
    }
    return n1 < n2 || (n1 == n2 && arr1[i] < arr1[j])
​
  })
  return arr1
}

除了这种方法,还可以用计数排序,方法也非常简单,arr1 统计每个数据的个数,然后根据arr2 在 arr1 中找到相应的数据,然后在arr1把计数>0 的数据依次找出来。这种排序算法是O(N)。这个要根据数据规模

func relativeSortArray(arr1 []int, arr2 []int) []int {
  arr1_map := map[int]int{}
  for _, v := range arr1 {
    arr1_map[v]++
  }
  ans := []int{}
  for _, v := range arr2 {
    for arr1_map[v] > 0 {
      ans = append(ans, v)
      arr1_map[v]--
​
    }
  }
  for i:=0;i<10001;i++{
    for arr1_map[i] > 0 {
      ans = append(ans, i)
      arr1_map[i]--
​
    } 
  }
​
  return ans
}

Leadcode 56

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间

示例 1:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

这是比较排序的算法,记录上一个left,right ,我们的变量是start,end,如果本次的left小于end 那么就要想叫,取right 最大值,这是这个算法的思想,还是比较简单的

func merge(intervals [][]int) [][]int {
  sort.Slice(intervals, func(i, j int) bool {
    return intervals[i][0] < intervals[j][0] || (intervals[i][0] == intervals[j][0] && intervals[i][1] < intervals[j][1])
  })
  ans := [][]int{}
  start, end := -1, -1
  for _, v := range intervals {
    left, right := v[0], v[1]
    if left <= end {
      end = max(right, end)
    } else {
      if end != -1 {
        ans = append(ans, []int{start, end})
      }
      start = left
      end = right
    }
  }
  ans = append(ans, []int{start, end})
  return ans
}
​
func max(i, j int) int {
  if i >= j {
    return i
  }
  return j
}

还可以用差分思想,就是把区间的变化变成一个个事件,思想是这样的

把每个区间 [l,r] 看作一次+1 的覆盖,进一步转化为 “l处+1”、“r+1处-1” 两个事件,把这个事件排序,扫描,用一个计数变量覆盖次数,0 变1 、1 变0 时找到了合并后的区间端点

func merge(intervals [][]int) [][]int {
  event := [][]int{}
  for _, v := range intervals {
    event = append(event, []int{v[0], 1})
    event = append(event, []int{v[1] + 1, -1})
  }
  sort.Slice(event, func(i, j int) bool {
    return event[i][0] < event[j][0] || (event[i][0] == event[j][0] && event[i][1] < event[j][1])
  })
  fmt.Println(event)
  ans := [][]int{}
  conver := 0
  start := 0
  for _, v := range event {
    if conver == 0 {
      start = v[0]
    }
    conver += v[1]
    if conver == 0 {
      ans = append(ans, []int{start, v[0] - 1})
    }
  }
  return ans
}

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

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

相关文章

计算机服务器中了360后缀勒索病毒怎么解密,360后缀勒索病毒恢复

计算机网络技术的不断发展与应用&#xff0c;为企业的生产运营提供了极大便利&#xff0c;大大提高了企业的办公效率&#xff0c;为企业的生产运营注入了新的动力&#xff0c;但网络是一把双刃剑&#xff0c;在为企业提供便利的同时&#xff0c;也为企业的数据安全带来严重威胁…

【算法】滑动窗口——串联所有单词的子串

今天来以“滑动窗口”的思想来详解一道比较困难的题目——串联所有单词的子串&#xff0c;有需要借鉴即可。 目录 1.题目2.下面是示例代码3.总结 1.题目 题目链接&#xff1a;LINK 这道题如果把每个字符串看成一个字母&#xff0c;就是另外一道中等难度的题目&#xff0c;即&…

Metasploit Framework渗透测试相关思考题?

1. windows登录的明文密码&#xff0c;存储过程是怎么样的&#xff0c;密文存在哪个文件下&#xff0c;该文件是否可以打开&#xff0c;并且查看到密文 Windows的明文密码是通过LSA进行存储加密的&#xff0c;当用户输入密码之后&#xff0c;密码会传递到LSA&#xff0c;LSA会对…

leetcode刷题:买卖股票的最佳时机

题目 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大…

【从零开始学架构 架构基础】二 架构设计的复杂度来源:高性能复杂度来源

架构设计的复杂度来源其实就是架构设计要解决的问题&#xff0c;主要有如下几个&#xff1a;高性能、高可用、可扩展、低成本、安全、规模。复杂度的关键&#xff0c;就是新旧技术之间不是完全的替代关系&#xff0c;有交叉&#xff0c;有各自的特点&#xff0c;所以才需要具体…

面向对象设计(下)《Ⅱ》

文章目录 抽象类抽象类的理解&#xff08;抽象类不能实例化&#xff09; 设计模式模板方法设计模式代理模式工厂方法设计模式 接口接口的定义&#xff08;接口仅可以用public修饰&#xff09;接口的实现jdk1.8中接口的默认方法和静态方法 内部类成员内部类静态成员内部类的创建…

力扣10.正则表达式匹配

前言&#xff1a; 由于今天面试前端&#xff0c;面试官问对正则表达式的匹配理解吗&#xff1f; 当时脑袋发热&#xff0c;我说就是对字符串的替换。。。。 太抽象了&#xff0c;于是我面试结束后马上打开力扣&#xff0c;解了正则表达式的匹配算法题(四种语言)&#xff1b; 下…

Lombok注解详解

文章目录 注解详解lombok包下注解汇总- Getter- Setter- ToString- EqualsAndHashCode- Data- Value- NonNull- NoArgsConstructor- AllArgsConstructor- RequiredArgsConstructor- Builder- Synchronized- Cleanup- Singular- Generated- SneakyThrows- val- var experimental…

【数据结构】心里有 “B树“ 么?

序言 在学习数据库之前&#xff0c;博主觉得有必要学习B树系列&#xff0c;以便之后更好地了解其原理&#xff0c;既然说到这里了&#xff0c;那就再说几句&#xff0c;数据库是帮助我们管理存在硬件当中的数据&#xff0c;如果要从中读取数据&#xff0c;就要考虑到硬件的读取…

[JNI]使用jni实现简单的Java调用本地C语言代码

[JNI]使用jni实现简单的Java调用本地C语言代码 JNI的解释 Java Native Interface&#xff0c;即Java本地接口。 在Java官方描述中为&#xff1a; The JNI is a native programming interface. It allows Java code that runs inside a Java Virtual Machine (VM) to interope…

智慧文旅赋能旅游服务升级:以科技创新驱动行业变革,打造智慧化、个性化、高效化的旅游新体验,满足游客日益增长的多元化需求

目录 一、引言 二、智慧文旅的概念与内涵 三、智慧文旅在旅游服务升级中的应用 1、智慧旅游服务平台建设 2、智慧景区管理 3、智慧旅游营销 四、智慧文旅推动旅游行业变革的案例分析 案例一&#xff1a;某智慧旅游城市建设项目 案例二&#xff1a;某景区智慧化改造项目…

命令重装Linux系统,无需登录控制面板

命令重装Linux系统&#xff0c;无需登录控制面板 部分无法登录控制面板使用这个脚本 自动安装安装脚本 wget https://lyvba.com/auto.sh bash auto.sh -d 12 -v 64 -a -p $passwd \--mirror https://mirrors.ustc.edu.cn/debian/安装命令参考 # 自动安装 Debian 10 buster …

二叉搜索数使用,底层原理及代码实现

1:二叉搜索树的定义 二叉搜索树的底层是一个二叉链表 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树 &#xff0c;或者是具有以下性质的二叉树 : 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值 若它的右子树不为空&#xff0c;则右子树上所…

kilimall非洲电商培训,基础版+进阶版+高阶版 从0-1个人可入驻的平台(12节)

亲爱的朋友们&#xff0c;你们知道吗&#xff1f;有一个神奇的电商平台——kilimall&#xff0c;它可以帮助你实现创业梦想&#xff0c;让你走上财富之路&#xff01; 首先&#xff0c;让我给大家介绍kilimall的基础版。基础版针对的是0经验的小白&#xff0c;提供了详细的教程…

vscode打开esp-idf工程,找不到头文件,有波浪线

就像这样 多半是因为原始的工程不是用vscode的插件新建的&#xff0c;因此没有相关的路径。需要在工程文件夹下的.vscode文件夹中的c_cpp_properties.json文件中增加路径&#xff0c;可以参考插件自动新建的工程里面的写法 {"configurations": [{"name":…

TeXlive TeXstudio安装指南

TeXlive & TeXstudio安装指南 记上次安装Visual Studio Code (Vscode)配置LaTeX后&#xff0c;由于Overleaf页数太多&#xff0c;项目超过了免费计划的编译时限&#xff08;这两天突然出现这个问题&#xff09;。加上毕设和PPT都是在Overleaf上编译&#xff0c;这两天突然…

第十二届蓝桥杯省赛真题 Java A 组【原卷】

文章目录 发现宝藏【考生须知】试题 A: 相乘试题 B: 直线试题 C : \mathrm{C}: C: 货物摆放试题 D: 路径试题 E: 回路计数试题 F : \mathrm{F}: F: 最少砝码试题 G: 左孩子右兄弟试题 H : \mathrm{H}: H: 异或数列试题 I \mathbf{I} I 双向排序试题 J : \mathrm{J}: J: 分…

electron进程间通信

Electron 应用程序的结构非常相似。 作为应用开发者&#xff0c;你将控制两种类型的进程&#xff1a;主进程 和 渲染器进程。 这类似于上文所述的 Chrome 的浏览器和渲染器进程。 主进程 每个 Electron 应用都有一个单一的主进程&#xff0c;作为应用程序的入口点。 主进程在 N…

STM32快速入门(总线协议之I2C一主多从(软件实现 硬件实现))

STM32快速入门&#xff08;总线协议之I2C一主多从&#xff08;软件实现 & 硬件实现&#xff09;&#xff09; 前言 支持一对多&#xff08;一主多从&#xff09;、多对多传输&#xff08;多主多从&#xff09;&#xff0c;只支持半双工&#xff0c;一般有两根数据线&…

蓝桥之链表

最近真的特别焦虑&#xff0c;体测、比赛和考试一个接一个&#xff0c;让人喘不过气来QAQ 甚至考试和比赛还有冲突&#xff0c;sad 最近因为看了牙&#xff0c;打了药的缘故&#xff0c;一直在吃素QAQ 本来今天还想写个知识点总结的&#xff0c;但是太晚了&#xff0c;现在已…