数据结构与算法之排序

server/2025/1/8 20:02:39/

9.1 排序的概念

1. 排序的定义
  • 定义:排序是将表中的记录按关键字递增(或递减)有序排列的过程。
  • 说明:数据中可以存在相同关键字的记录。本章主要考虑递增排序。
  • 扩展:排序是数据处理中的基本操作之一,广泛应用于数据库管理、信息检索等领域。排序可以提高数据的可读性和可操作性,便于后续的查找、统计等操作。
2. 内排序和外排序
  • 内排序:整个表都在内存中处理,不涉及数据的内外存交换。
  • 外排序:排序过程中需要进行数据的内外存交换。
  • 扩展:内排序适用于数据量较小的情况,因为内存访问速度快,效率较高。外排序适用于数据量较大的情况,通常需要将数据分块处理,然后合并排序结果。
3. 内排序的分类
  • 插入排序:通过将元素插入到已排序部分的适当位置来实现排序。
  • 交换排序:通过交换元素的位置来实现排序,如冒泡排序。
  • 选择排序:通过选择未排序部分的最小(或最大)元素与当前元素交换来实现排序。
  • 归并排序:将数据分成多个小部分进行排序,然后将排序好的部分合并。
  • 基于比较的算法>排序算法:如插入排序、交换排序、选择排序、归并排序等。
  • 不基于比较的算法>排序算法:如基数排序。
  • 扩展:不同的算法>排序算法适用于不同的场景,选择合适的算法>排序算法可以提高程序的效率。例如,插入排序适用于部分有序的数据,而归并排序适用于大规模数据的排序.
4.小结
  • 排序的概念定义递增或递减排列
      • 允许相同关键字
    • 内排序 vs 外排序内排序:内存中处理
      • 外排序:内外存交换
    • 内排序分类插入排序
      • 交换排序
      • 选择排序
      • 归并排序
      • 基数排序

9.2插入排序

9.2.1 直接插入排序
基本思路
  • 有序区和无序区:初始时,有序区只有一个元素(通常是第一个元素),无序区包含其余所有元素。
  • 排序过程:每次从未排序区取出一个元素,插入到有序区的适当位置,使得有序区仍然保持有序。
  • 步骤将待插入元素与有序区的元素从后向前比较。
    • 如果待插入元素小于当前比较的元素,则将当前元素后移一位。
    • 重复上述步骤,直到找到待插入元素的正确位置。
    • 将待插入元素插入到该位置。
Python实现

def insert_sort(arr):for i in range(1, len(arr)):
        key = arr[i]
        j = i - 1# 将arr[i]插入到已排序序列arr[0...i-1]中while j >= 0 and key < arr[j]:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = keyreturn arr# 示例
arr = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print("原始数组:", arr)
insert_sort(arr)
print("排序后的数组:", arr)

算法分析
  • 时间复杂度最好情况:输入序列已经是正序的,时间复杂度为 O(n)。
    • 最坏情况:输入序列是反序的,时间复杂度为 O(n2)。
    • 平均情况:时间复杂度为 O(n2)。
  • 空间复杂度O(1),因为只需要一个额外的变量来存储待插入的元素。
  • 稳定性:稳定算法>排序算法,因为相同元素的相对顺序不会改变。

eg设待排序的表有10个元素,其关键字分别为(9,8,7,6,5,4,3,2,1,0)

9.2.2 折半插入排序

基本思路
  • 折半查找:在有序区中使用折半查找方法来确定待插入元素的位置,从而减少比较次数。
  • 步骤将待插入元素保存在一个临时变量中。
    • 使用折半查找在有序区中找到待插入元素的正确位置。
    • 将有序区中从插入位置开始的所有元素后移一位,为待插入元素腾出空间。
    • 将待插入元素插入到找到的位置。
Python实现

def binary_search(arr, key, low, high):while low <= high:
        mid = (low + high) // 2if arr[mid] < key:
            low = mid + 1else:
            high = mid - 1return lowdef binary_insert_sort(arr):for i in range(1, len(arr)):
        key = arr[i]# 使用折半查找找到插入位置
        pos = binary_search(arr, key, 0, i - 1)# 将元素后移for j in range(i, pos, -1):
            arr[j] = arr[j - 1]# 插入元素
        arr[pos] = keyreturn arr# 示例
arr = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print("原始数组:", arr)
binary_insert_sort(arr)
print("排序后的数组:", arr)

算法分析
  • 时间复杂度比较次数:由于使用了折半查找,比较次数为 O(logn)。
    • 移动次数:移动次数仍为 O(n),因为需要将元素后移。
    • 总时间复杂度O(n2),虽然比较次数减少,但移动次数仍然较高。
  • 空间复杂度O(1),只需要一个额外的变量来存储待插入的元素。
  • 稳定性:稳定算法>排序算法,因为相同元素的相对顺序不会改变.

9.2.3 希尔排序

基本思路
  • 分组插入:希尔排序是一种基于插入排序的改进算法,通过将待排序序列分成若干个子序列,对每个子序列进行直接插入排序。
  • 增量序列:选择一个增量序列 d1,d2,,dkd1 ,d2 ,,dk ,其中 d1>d2>>dk=1d1 >d2 >>dk =1。增量 dd 通常从 n/2n/2 开始,每次减半,直到增量为1。
  • 步骤选择一个增量 dd,将待排序序列分成 dd 个子序列。
    • 对每个子序列进行直接插入排序。
    • 减小增量 dd,重复上述步骤,直到增量为1。
Python实现

def shell_sort(arr):
    n = len(arr)
    gap = n // 2  # 初始增量while gap > 0:for i in range(gap, n):
            temp = arr[i]
            j = i# 对每个子序列进行插入排序while j >= gap and arr[j - gap] > temp:
                arr[j] = arr[j - gap]
                j -= gap
            arr[j] = temp
        gap //= 2  # 减小增量return arr# 示例
arr = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print("原始数组:", arr)
shell_sort(arr)
print("排序后的数组:", arr)

算法分析
  • 时间复杂度最好情况O(nlogn)O(nlogn),当增量序列选择得当且数据接近有序时。
    • 最坏情况O(n2)O(n2),但通常比直接插入排序要好。
    • 平均情况:通常为 O(n1.3)O(n1.3) O(n1.5)O(n1.5),具体取决于增量序列的选择。
  • 空间复杂度O(1)O(1),因为只需要一个额外的变量来存储待插入的元素。
  • 稳定性:不稳定算法>排序算法,因为相同元素的相对顺序可能会改变.

希尔排序过程解释

  1. 初始序列9, 8, 7, 6, 5, 4, 3, 2, 1, 0
  2. 第一次排序(d=5)
    1. 增量 d 被设置为数组长度的一半,即 5
    2. 将数组分为 5 组,每组包含相隔 5 个位置的元素:{9, 4}, {8, 3}, {7, 2}, {6, 1}, {5, 0}
    3. 对每组进行直接插入排序。例如,第一组 9, 4 排序后变为 4, 9
    4. 数组变为4938271605
  3. 第二次排序(d=2)
    1. 增量 d 减半,变为 2
    2. 将数组分为 2 组,每组包含相隔 2 个位置的元素:{4, 3, 2, 1}, {9, 8, 7, 6}, {5, 0}
    3. 对每组进行直接插入排序。例如,第一组 4, 3, 2, 1 排序后变为 1, 2, 3, 4
    4. 数组变为1234678905
  4. 第三次排序(d=1)
    1. 增量 d 再次减半,变为 1因为整一个数组基本有序,最后进行一次直接插入排序时间复杂度就约等于O(n),在这里除了0和5其它元素都是直接放入有序区。
    2. 此时,整个数组作为一个组进行直接插入排序。
    3. 由于前两次排序已经将数组中的元素大致排列好了,这次排序将它们排列成完全有序的序列:0, 1, 2, 3, 4, 5, 6, 7, 8, 9


http://www.ppmy.cn/server/156869.html

相关文章

学英语学压测:02jmeter组件-测试计划和线程组ramp-up参数的作用

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#xff1a;先看关键单词&#xff0c;再看英文&#xff0c;最后看中文总结&#xff0c;再回头看一遍英文原文&#xff0c;效果更佳&#xff01;&#xff01; 关键词 Functional Testing功能测试[ˈfʌŋkʃənəl ˈtɛstɪŋ]Sample样…

SpringBoot安装及配置

1 Spring Boot介绍 Spring让Java程序更加快速, 简单和安全. Spring对于速度、简单性和⽣产⼒的关注使其成为世界上最流⾏的Java框架。 这些项⽬都是基于Spring Framework来进⾏开发的, 但是Spring Framework存在配置多, ⼊⻔难的问题, Spring 也意识到了这个问题, 为了简化开…

电脑硬盘系统迁移及问题处理

一、系统迁移准备 1、确认你的电脑主板是否支持安装两块硬盘,如电脑主板有多个M2硬盘接口,我们将新硬盘安装到主板上,原来的老硬盘安装在第二个接口上,主板只有一个M2接口的话可以使用移动硬盘盒。 2、新硬盘安装好后,我们进入原来的系统,在 此电脑–右键–管理–磁盘管…

英伟达 RTX 5090 显卡赋能医疗大模型:变革、挑战与展望

一、英伟达 RTX 5090 与 RTX 4090 技术参数对比 1.1 核心架构与制程工艺 在探讨英伟达 RTX 4090 与 RTX 5090 的差异时&#xff0c;核心架构与制程工艺无疑是最为关键的基础要素&#xff0c;它们从根本上决定了两款显卡的性能上限与应用潜力。 1.1.1 核心架构差异 RTX 4090…

计算机网络——数据链路层-流量控制和可靠传输

一、流量控制 流量控制是指由接收方及时控制发送方发送数据的速率&#xff0c;使接收方来得及接受。 • 停止等待流量控制 • 滑动窗口流量控制 1、停止—等待流量控制 停止-等待流量控制的基本原理是发送方每发出一帧后&#xff0c;就要等待接收方的应答信号&#xff…

关于Redis的面试题目及其答案

什么是Redis&#xff1f; Redis是一个开源的、基于键值对存储的NoSQL数据库&#xff0c;常用于缓存、会话存储和消息队列系统。 Redis为什么这么快&#xff1f; Redis之所以快是因为它使用内存作为主要存储介质&#xff0c;并且采用了单线程模型避免了多线程的上下文切换开销。…

HCIA-Access V2.5_8_1_EPON原理_PON基本概念

前言 考虑到未来许多带宽的应用&#xff0c;越来越多的国家认识到必须尽早突破接入瓶颈&#xff0c;铜缆的xDSL技术已经走到了尽头&#xff0c;而光纤是迄今发现的最好的传输介质&#xff0c;所以PON网络的应用也是越来越多&#xff0c;本章主要介绍EPON系统原理及相关技术&…

【力扣热题100】—— Day18.将有序数组转换为二叉搜索树

期末考试完毕&#xff0c;假期学习开始&#xff01; —— 25.1.7 108. 将有序数组转换为二叉搜索树 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵平衡二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] …