【16】数据结构之基于树的排序算法篇章

news2025/4/16 13:26:56

目录标题

  • 选择排序
    • 简单选择排序
    • 树形选择排序
  • 堆排序
    • 堆的定义Heap
      • 小跟堆
      • 大根堆
      • 堆的存储
      • 堆的代码设计
      • 堆排序的代码设计
    • 排序算法综合比较

选择排序

  • 基本思想:从待排序的序列中选出最大值或最小值,交换该元素与待排序序列的头部元素,对剩下的元素重复操作,直到完成所有元素排序.

简单选择排序

  • 第i次排序通过n-i次关键字的比较,从n-i+1个元素中选出关键字最小的元素,并和第i个元素交换.共需进行i-1次比较,直到所有元素排序完成为止.
  • 示意图
    在这里插入图片描述
  • 代码实现与调试
# 树的排序--简单选择排序
class SelectSort(object):
    def __init__(self, items):
        # 待排序的序列
        self.items = items

    def selectSort(self):
        """
        简单选择排序
        :return:
        """
        # 共n轮排序
        for i in range(len(self.items)):
            # 待交换的元素
            index = i
            # 在未排序的序列中选取最小的元素
            for j in range(i+1, len(self.items)):
                if self.items[j] < self.items[index]:
                    index = j
            # 最小的元素不是带交换的元素,则两者交换
            if index != i:
                self.items[i],self.items[index] = self.items[index],self.items[i]
             
if __name__ == "__main__":
	arr = [84, 62, 35, 77, 55, 14, 35, 98]
    select = SelectSort(arr)
    select.selectSort()
    print(arr)

树形选择排序

  • 树形选择排序也称锦标赛排序.
  • 首先所有参加比赛的选手两两分组,每组产生一个胜利者,然后这些胜利者再两两分组进行比赛,每组产生一个胜利者,之后重复执行,直到最后只有一个胜利者为止.
  • 示意图
    在这里插入图片描述
  • 代码实现与调试
class TournamentSort:
    def __init__(self, arr):
        self.original = arr.copy()
        self.n = len(arr)
        # 初始化所有属性,确保空数组时属性存在
        self.leaf_size = 0
        self.tree_size = 0
        self.tree = []

        if self.n == 0:
            return  # 空数组直接返回

        # 计算扩展到下一个2的幂次方的叶子数量
        self.leaf_size = 1 << (self.n - 1).bit_length()
        self.tree_size = 2 * self.leaf_size - 1

        # 初始化树结构并用inf填充空位
        self.tree = [float('inf')] * self.tree_size
        # 将原始数据填充到叶子节点
        self.tree[-self.leaf_size: -self.leaf_size + self.n] = self.original

        # 构建初始锦标赛树(自底向上)
        for i in range(self.tree_size - 1, 0, -1):
            if i % 2 == 1:  # 只处理左子节点,避免重复计算
                parent = (i - 1) // 2
                self.tree[parent] = min(self.tree[i], self.tree[i + 1])

    def get_min(self):
        """获取当前最小值并重构树"""
        if self.n <= 0:
            return None

        winner = self.tree[0]
        # 查找叶子层中的最小值位置
        idx = self.tree_size // 2  # 叶子层起始索引
        while idx < self.tree_size:
            if self.tree[idx] == winner:
                break
            idx += 1

        # 标记该位置为已选中
        self.tree[idx] = float('inf')
        self.n -= 1

        # 自底向上更新树结构
        while idx > 0:
            parent = (idx - 1) // 2
            sibling = idx + 1 if idx % 2 == 1 else idx - 1
            self.tree[parent] = min(self.tree[idx], self.tree[sibling])
            idx = parent

        return winner

    def sort(self):
        """执行完整排序过程"""
        sorted_arr = []
        while True:
            val = self.get_min()
            if val is None:
                break
            sorted_arr.append(val)
        return sorted_arr

    def print_tree(self):
        """可视化打印树结构(调试用)"""
        print("当前锦标赛树结构:")
        if self.tree_size == 0:
            print("空树")
            return
        level = 0
        level_size = 1
        while level_size <= self.tree_size:
            start = 2 ** level - 1
            end = start + level_size
            print(f"Level {level}: {self.tree[start:end]}")
            level += 1
            level_size *= 2


# ---------------------- 测试用例 ----------------------
if __name__ == "__main__":
	test_cases = [
        [3, 1, 4, 1, 5, 9, 2, 6],  # 常规测试
        [9, 3, 5, 2, 8],  # 奇数元素
        [5, 3, 8, 6, 2],  # 重复值测试
        [1],  # 单个元素
        []  # 空数组
    ]

    for i, case in enumerate(test_cases):
        print(f"\n测试用例 {i + 1}: {case}")
        ts = TournamentSort(case)
        ts.print_tree()  # 调试查看初始树结构

        sorted_result = ts.sort()
        print(f"排序结果: {sorted_result}")
        print("验证结果:", "正确" if sorted_result == sorted(case) else "错误")

堆排序

  • 对树形选择排序的一种改进

堆的定义Heap

  • 堆是二叉树的一种
  • 堆是完全二叉树
  • 堆中任意结点的值总是不大于或者不小于其双亲结点的值
  • 堆分为大根堆和小跟堆

小跟堆

  • 如果根结点存在左孩子结点,则根结点的值小于或等于左孩子结点的值
  • 如果根结点存在右孩子结点,则根结点的值小于或等于右孩子结点的值
  • 根结点的左右子树也是小跟堆
  • 小跟堆示意图
    在这里插入图片描述

大根堆

  • 如果根结点存在左孩子结点,则根结点的值大于或等于左孩子结点的值
  • 如果根结点存在右孩子结点,则根结点的值大于或等于右孩子结点的值
  • 根结点的左右子树也是大跟堆
  • 大跟堆示意图
    在这里插入图片描述

堆的存储

  • 常用顺序结构进行存储.
  • 重建堆方法
    • 首先将完全二叉树根结点中的元素移出,
    • 从空结点的左右孩子结点中选出一个关键字较小的元素,上移到空结点中,
    • 当前那个较小关键字较小的子结点相当于空结点,
    • 重复上述移动原则
    • 直到空结点的左右孩子结点的关键字均不小于待调整元素的关键字为止
  • 建立初始堆算法思路
    • 一个任意序列可以看成对应的完全二叉树,由于叶子结点可以视为单元素的堆,然后反复利用重建堆方法,自底向上逐层把所有子树调整为堆,直到将整个完全二叉树调整为堆为止

堆的代码设计

class Heap:
    def __init__(self, items=[]):
        self.items = items.copy()
        self.build_min_heap()

    def build_min_heap(self):
        """将列表初始化为小根堆"""
        length = len(self.items)
        for i in range(length // 2 - 1, -1, -1):
            self._sift_down(i, length)

    def insert(self, key):
        """插入新元素并上浮调整"""
        self.items.append(key)
        self._sift_up(len(self.items) - 1)

    def delete(self):
        """删除堆顶元素"""
        if not self.items:
            raise IndexError("堆为空,无法删除")

        # 将最后一个元素移到堆顶
        removed = self.items[0]
        self.items[0] = self.items[-1]
        self.items.pop()

        # 下沉调整
        if self.items:
            self._sift_down(0, len(self.items))
        return removed

    def _sift_up(self, index):
        """元素上浮操作"""
        parent = (index - 1) // 2
        while parent >= 0 and self.items[index] < self.items[parent]:
            self.items[index], self.items[parent] = self.items[parent], self.items[index]
            index = parent
            parent = (index - 1) // 2

    def _sift_down(self, index, size):
        """元素下沉操作"""
        smallest = index
        left = 2 * index + 1
        right = 2 * index + 2

        if left < size and self.items[left] < self.items[smallest]:
            smallest = left
        if right < size and self.items[right] < self.items[smallest]:
            smallest = right

        if smallest != index:
            self.items[index], self.items[smallest] = self.items[smallest], self.items[index]
            self._sift_down(smallest, size)

    def __str__(self):
        return str(self.items)


# ---------------------- 测试用例 ----------------------
if __name__ == "__main__":
    # 测试初始化与插入删除
    heap = Heap([10, 25, 15, 40, 25, 20, 30, 50, 55])
    print("初始堆:", heap)  # 输出: [10, 25, 15, 40, 25, 20, 30, 50, 55]

    heap.insert(9)
    print("插入9后:", heap)  # 输出: [9, 25, 10, 40, 55, 15, 30, 50, 25, 20]

    val = heap.delete()
    print(f"删除元素 {val} 后:", heap)  # 删除9后:[10, 25, 15, 40, 55, 20, 30, 50, 25]

    val = heap.delete()
    print(f"删除元素 {val} 后:", heap)  # 删除10后:[15, 25, 20, 40, 25, 55, 30, 50]

    # 测试空堆
    empty_heap = Heap()
    try:
        empty_heap.delete()
    except IndexError as e:
        print("空堆删除测试:", e)  # 输出:堆为空,无法删除

    # 测试单元素堆
    single_heap = Heap([5])
    single_heap.delete()
    print("单元素堆删除后:", single_heap)  # 输出:[]

堆排序的代码设计

class HeapSort:
    def __init__(self, items):
        self.items = items  # 初始化待排序数组

    def heapSort(self):
        """堆排序主方法"""
        length = len(self.items)

        # 1. 构建最大堆(从最后一个非叶子节点开始调整)
        for i in range(length // 2 - 1, -1, -1):
            self._adjust_max_heap(self.items, i, length)

        # 2. 排序阶段(依次将堆顶元素移到末尾)
        for i in range(length - 1, 0, -1):
            # 交换堆顶(最大值)与当前末尾元素
            self.items[0], self.items[i] = self.items[i], self.items[0]
            # 调整剩余堆结构(堆大小逐渐减小)
            self._adjust_max_heap(self.items, 0, i)

    def _adjust_max_heap(self, arr, root, heap_size):
        """调整最大堆(递归实现)"""
        largest = root  # 初始化最大值为根节点
        left = 2 * root + 1  # 左子节点索引
        right = 2 * root + 2  # 右子节点索引

        # 比较左子节点
        if left < heap_size and arr[left] > arr[largest]:
            largest = left

        # 比较右子节点
        if right < heap_size and arr[right] > arr[largest]:
            largest = right

        # 如果最大值位置变化,交换并递归调整子树
        if largest != root:
            arr[root], arr[largest] = arr[largest], arr[root]
            self._adjust_max_heap(arr, largest, heap_size)


# ---------------------- 测试用例 ----------------------
if __name__ == "__main__":
    nums = [40, 55, 73, 12, 98, 27]
    sorter = HeapSort(nums)
    sorter.heapSort()
    print("排序结果:", nums)  # 输出: [12, 27, 40, 55, 73, 98]

排序算法综合比较

在这里插入图片描述

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

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

相关文章

华熙生物亮相消博会,这次又带来了什么样的变化?

首先&#xff0c;从展示层面来看&#xff0c;华熙生物在消博会上构建科技桥梁&#xff0c;展台主视觉展示糖生物学发展历程与自身发展交织历程&#xff0c;这象征着中国生物科技企业从产业突围到定义全球标准的蜕变。这一展示不仅提升了华熙生物的品牌形象&#xff0c;更向外界…

大象机器人推出myCobot 280 RDK X5,携手地瓜机器人共建智能教育机

摘要 大象机器人全新推出轻量级高性能教育机械臂 myCobot 280 RDK X5&#xff0c;该产品集成地瓜机器人 RDK X5 开发者套件&#xff0c;深度整合双方在硬件研发与智能计算领域的技术优势&#xff0c;实现芯片架构、软件算法、硬件结构的全栈自主研发。作为国内教育机器人生态合…

【初阶数据结构】——算法复杂度

一、前言 1、数据结构是什么&#xff1f; 数据结构(Data Structure)是计算机存储、组织数据的⽅式&#xff0c;指相互之间存在⼀种或多种特定关系的数 据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤&#xff0c;所以我们要学各式各样的数据结构&#xff0c; 如&…

Google-A2A协议全面解析:一文掌握Agent-to-Agent协议的核心与应用

前言&#xff1a; 在当今人工智能技术飞速发展的时代&#xff0c;智能体&#xff08;Agent&#xff09;已悄然融入我们生活的各个角落。无论是个人智能助手&#xff0c;还是企业的自动化工具&#xff0c;各类AI代理的应用愈发广泛。但目前这些智能体之间大多处于孤立状态&…

Linux-服务器添加审计日志功能

#查看audit软件是否在运行(状态为active而且为绿色表示已经在运行) systemctl start auditd #如果没有在运行的话,查看是否被系统禁用 (audit为0表示被禁用) cat /proc/cmdline | grep -w "audit=0" #修改/etc/default/grub里面audit=0 改为audit=1 #更新GRUB…

基于机器视觉的多孔零件边缘缺陷检测(源码C++、opencv、凸包、凸缺陷检测)

&#x1f451;主页&#xff1a;吾名招财 &#x1f453;简介&#xff1a;工科学硕&#xff0c;研究方向机器视觉&#xff0c;爱好较广泛… ​&#x1f4ab;签名&#xff1a;面朝大海&#xff0c;春暖花开&#xff01; 基于机器视觉的多孔零件边缘缺陷检测&#xff08;源码C、ope…

如何使用AI辅助开发CSS3 - 通义灵码功能全解析

一、引言 CSS3 作为最新的 CSS 标准&#xff0c;引入了众多新特性&#xff0c;如弹性布局、网格布局等&#xff0c;极大地丰富了网页样式的设计能力。然而&#xff0c;CSS3 的样式规则繁多&#xff0c;记忆所有规则对于开发者来说几乎是不可能的任务。在实际开发中&#xff0c…

MySQL入门:数据表的创建

​今天我们来介绍一下除HTML外的另一种语言&#xff1a;MySQL语言&#xff1b; MySQL&#xff1a;即一种用于管理和处理关系数据库的标准语言。要用于执行查询、更新、管理数据库中的数据以及定义和操作数据库结构。 接下来我会逐一介绍它的作用以及其中数据表&#xff0c;数据…

数据库的基本原则

数据库的核心原则 原子性与持久性&#xff1a;原子性&#xff08;Atomicity&#xff09;确保一个事务中的所有操作要么全部完成&#xff0c;要么完全不执行&#xff0c;不会出现部分完成的情况。持久性&#xff08;Durability&#xff09;则保证一旦事务提交成功&#xff0c;即…

Rust 中的Relaxed 内存指令重排演示:X=0 Y=0 是怎么出现的?

&#x1f525; Rust 中的内存重排演示&#xff1a;X0 && Y0 是怎么出现的&#xff1f; 在并发编程中&#xff0c;我们经常会听说“内存重排&#xff08;Memory Reordering&#xff09;”这个术语&#xff0c;但它似乎总是只出现在理论或者别人口中的幻觉里。本文将通过…

C++进程间通信开发实战:高效解决项目中的IPC问题

C进程间通信开发实战&#xff1a;高效解决项目中的IPC问题 在复杂的软件项目中&#xff0c;进程间通信&#xff08;Inter-Process Communication, IPC&#xff09;是实现模块化、提高系统性能与可靠性的关键技术之一。C作为一门高性能的编程语言&#xff0c;广泛应用于需要高效…

FPGA-DDS技术的波形发生器

1.实验目的 1.1掌握直接数字频率合成&#xff08;DDS&#xff09;的基本原理及其实现方法。 1.2在DE2-115 FPGA开发板上设计一个可调频率的正弦波和方波发生器&#xff0c;频率范围10Hz~5MHz&#xff0c;最小分辨率小于1kHz。 1.3使用Quartus II进行仿真&#xff0c;并通过S…

C#实现通过MQTT Broker——EMQX发布订阅消息及其认证、授权的安全配置操作

一、准备内容 MQTT的构成、使用场景、工作原理介绍-CSDN博客文章浏览阅读656次,点赞7次,收藏12次。MQTT(Message Queuing Telemetry Transport)是一种轻量级、基于发布-订阅模式的消息传输协议【适用于资源受限的设备和低带宽、高延迟或不稳定的网络环境】它在物联网应用中…

【双指针】三数之和(medium)

三数之和&#xff08;medium&#xff09; 题⽬描述&#xff1a;解法&#xff08;排序双指针&#xff09;&#xff1a;算法思路&#xff1a;C 算法代码&#xff1a;Java 算法代码&#xff1a;注&#xff1a;数组转列表 题⽬链接&#xff1a;15. 三数之和 题⽬描述&#xff1a; …

【项目管理】第17章 项目干系人管理-- 知识点整理

项目管理-相关文档,希望互相学习,共同进步 风123456789~-CSDN博客 (一)知识总览 项目管理知识域 知识点: (项目管理概论、立项管理、十大知识域、配置与变更管理、绩效域) 对应:第6章-第19章 第6章 项目管理概论 4分第13章 项目资源管理 3-4分第7章 项目…

视频融合平台EasyCVR可视化AI+视频管理系统,打造轧钢厂智慧安全管理体系

一、背景分析 在轧钢厂&#xff0c;打包机负责线材打包&#xff0c;操作人员需频繁进入内部添加护垫、整理包装、检修调试等。例如&#xff0c;每班产线超过300件&#xff0c;12小时内人员进出打包机区域超过300次。若员工安全意识薄弱、违规操作&#xff0c;未落实安全措施就…

无参数RCE

无参数RCE&#xff08;Remote Code Execution&#xff0c;远程代码执行&#xff09; 是一种通过利用目标系统中的漏洞&#xff0c;在不直接传递用户可控参数的情况下&#xff0c;实现远程执行任意代码的攻击技术。与传统的RCE攻击不同&#xff0c;无参数RCE不依赖外部输入参数…

C++ 智能指针底层逻辑揭秘:优化内存管理的核心技术解读

目录 0.为什么需要智能指针&#xff1f; 1.智能指针的使用及原理 RAII&#xff1a; 智能指针的原理&#xff1a; 2.智能指针有哪些&#xff1f; std::auto_ptr std::unique_ptr std::shared_ptr std::weak_ptr 0.为什么需要智能指针&#xff1f; 想要回答这个问题&…

Vue接口平台学习七——接口调试页面请求体

一、实现效果图及简单梳理 请求体部分的左边&#xff0c;展示参数&#xff0c;分text和file类型。 右边部分一个el-upload的上传文件按钮&#xff0c;一个table列表展示&#xff0c;一个显示框&#xff0c;用于预览选择的文件&#xff0c;点击可大图展示。 二、页面内容实现 …

小程序css实现容器内 数据滚动 无缝衔接 点击暂停

<view class"gundongBox"><!-- 滚动展示信息的模块 --><image class"imgWid" :src"imgurlgundong.png" mode"widthFix"></image><view class"gundongView"><view class"container&qu…