04树 + 堆 + 优先队列 + 图(D1_树(D6_B树(B)))

目录

一、学习前言

二、基本介绍

三、特性

1. 从概念上说起

2. 举个例子

四、代码实现

节点准备

大体框架

实现分裂

实现新增

实现删除

五、完整源码


一、学习前言

前面我们已经讲解过了二叉树、二叉搜索树(BST)、平衡二叉搜索树(AVL树)、红黑树,接下

爱就让我们了解下B树到底是什么?

二、基本介绍

在计算机科学中,B树是一种自平衡的树形数据结构,能够保持数据有序。

这种数据结构能够让查找数据、顺序访问、插入数据及删除的动作,都在对数量级的时间复杂度内

完成。

  • B树,其实是一颗特殊的二叉查找树(binary search tree),可以拥有多于2个子节点。与自平衡二叉查找树不同,B树为系统大块数据的读写操作做了优化。
  • B树减少定位记录时所经历的中间过程,从而加快存取速度,其实B树主要解决的就是数据IO的问题。
  • 树这种数据结构可以用来描述外部存储。这种数据结构常被应用在数据库和文件系统的实现上。

总而言之,B树主要用于管理磁盘上的数据管理(减少磁盘IO次数),而之前说的AVL树与红黑树

适合用于内存数据管理。例如:存储一个100w的数据使用AVL存储,树高大约为20层(),如果使用磁盘IO查询20次效率较低。

注意:常常面试官会问B树和B-树的区别,我们该如何回答?其实,B树和B-树是同一种数据结

构,如果不清楚的话,会被面试官忽悠!

三、特性

1. 从概念上说起

度degree:指树中节点孩子数

阶order:指所有节点孩子数中最大值

一棵 B-树具有以下性质

特性1:每个节点 x 具有

  • 属性 n,表示节点 x 中 key 的个数
  • 属性 leaf,表示节点是否是叶子节点
  • 节点 key 可以有多个,以升序存储

特性2:每个节点最多具有m个孩子,其中m叫做B-树的阶

特性3:除根结点与叶子节点外,每个节点至少有ceil(m/2)个孩子,根节点不是叶子节点时,最少

有两个孩子。叶子节点没有孩子

特性4:每个非叶子节点中的孩子数是 n + 1。而n的取值为ceil(m/2)-1<=n<=m-1。

特性5:最小度数t(节点的孩子数称为度)和节点中键数量的关系如下:

最小度数t

键数量范围

2

1 ~ 3

3

2 ~ 5

4

3 ~ 7

...

...

n

(n-1) ~ (2n-1)

其中,当节点中键数量达到其最大值时,即 3、5、7 ... 2n-1,需要分裂

特性6:叶子节点的深度都相同

2. 举个例子

一个m阶的B树特点如下:

  1. 所有叶子节点都在同一层级;
  2. 除了根节点以外的其他节点包含的key值数量在[m/2]-1到m-1的数据范围;
  3. 除了根节点和叶子节点外,所有中间节点至少有m/2个孩子节点;
  4. 根节点如果不是叶子节点的话,它必须包含至少2个孩子节点;
  5. 拥有n-1个key值非叶子节点必须有n个孩子节点;
  6. 一个节点的所有key值必须是升序排序的;

以上六点就是B树的全部特性

四、代码实现

节点准备

B树的节点属性,与其他树不太相同,首先是key可以有多个,因此要设置为数组,孩子节点也未

知,因此也要设置为数组。

本应该还存在一个value属性,这里简化掉,不添加该属性。

static class Node {
    boolean leaf = true; //是否是叶子节点
    int keyNumber; //有效key
    int t; //最小度
    int[] keys; // keys数组
    Node[] children; //孩子节点数组
 
    public Node(int t) {
        this.t = t;
        this.keys = new int[2 * t - 1];
        this.children = new Node[2 * t];//最大孩子节点个数为为2*t
    }
 
    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOfRange(keys, 0, keyNumber));
    }
 
    /**
     * 根据key获取对应节点
     *
     * @param key
     * @return
     */
    Node get(int key) {
        int i = 0;
        while (i < keyNumber) {
            //如果在该节点找到,那么直接返回即可
            if (keys[i] == key) {
                return this;
            }
            //说明要找的元素可能在children[i]中
            if (keys[i] > key) {
                break;
            }
            i++;
        }
        //如果是叶子节点,直接返回null
        if (leaf) {
            return null;
        }
        return children[i].get(key);
    }
 
    /**
     * 指定位置插入元素
     *
     * @param key
     * @param index
     */
    void insertKey(int key, int index) {
        System.arraycopy(keys, index, keys, index + 1, keyNumber - index);
        keys[index] = key;
        keyNumber++;
    }
 
    /**
     * 向节点中插入孩子节点
     * @param child
     * @param index
     */
    void insertChild(Node child, int index) {
        System.arraycopy(children, index, children, index + 1, keyNumber - index);
        children[index] = child;
    }
}

这里我采用了静态数组,因此需要多添加一个keyNumber参数来获取有效key的数量,如果使用

ArrayList,可以通过size方法获取,因此不需要添加这个属性。

大体框架

public class BTree {
    private Node root;
    private int t;//最小度数
    final int MAX_KEY_NUMBER;//最大key数量
    final int MIN_KEY_NUMBER;//最小key数量。用于分裂使用
 
    public BTree(int t) {
        this.t = t;
        root = new Node(t);
        MAX_KEY_NUMBER = 2 * t - 1;
        MIN_KEY_NUMBER = 2 * t;
    }
 
    static class Node {
        boolean leaf = true; //是否是叶子节点
        int keyNumber; //有效key
        int t; //最小度
        int[] keys; // keys数组
        Node[] children; //孩子节点数组
 
        public Node(int t) {
            this.t = t;
            this.keys = new int[2 * t - 1
<think>好的,我现在需要帮助用户理解如何绘制他们VHDL代码实现的采样队列和平均值计算的逻辑。首先,我得先回忆一下VHDL的基本结构以及采样队列和平均值计算的常见实现方式。用户可能已经写好了代码,但需要将其转化为逻辑,这通常涉及数据流和控制流的可视化。 首先,采样队列通常使用移位寄存器或者FIFO(先进先出)结构来实现。每个时钟周期,新的采样数据会被移入队列,同时旧的移出。平均值计算如果是滑动平均的话,可能就是将队列中的所有数据相加然后除以数量。需要考虑的是,队列的长度是多少,是固定还是可变的?这可能影响逻辑中的模块设计。 接下来是平均值计算部分。如果是定点数,可能需要加法器和除法器,或者为了优化资源使用累加器和移位操作(如果队列长度是2的幂次)。比如,8个数据的平均可以用累加后右移3位来代替除法。这部分在逻辑中应该显示加法器、累加器以及可能的移位器。 然后,控制逻辑部分,比如时钟信号、复位信号,以及何时触发采样和计算。控制模块可能生成使能信号,控制队列的移位和累加器的清零。状态机可能在逻辑中作为一个单独的模块出现,管理各个步骤的时序。 用户可能还需要考虑数据宽度,比如采样数据是8位还是16位,这会影响到加法器的位数和溢出处理。逻辑中应标明各个模块的数据宽度,例如8位输入,经过累加后可能扩展到12位等。 此外,时序问题也很重要。采样队列在什么时候移入新数据?平均值计算是在每个采样周期后立即进行,还是在特定条件下触发?这些时序控制信号需要在逻辑中体现,比如时钟边沿触发的寄存器,或者使能信号的控制路径。 可能的疑问点:用户是否使用了同步复位或异步复位?这会影响到控制逻辑的设计。另外,如何处理队列满的情况?是否需要溢出指示?这些细节可能需要用户进一步澄清,但假设代码中已经处理了这些情况,逻辑应包含相应的信号线。 最后,绘制逻辑的工具方面,用户可能需要推荐一些工具,比如Visio、Draw.io,或者专业的EDA工具如Quartus的RTL Viewer。不过用户的问题主要集中在如何绘制,而不是工具选择,所以重点应放在模块和信号连接上。 总结一下,逻辑需要包括以下部分:采样队列模块(移位寄存器或FIFO)、累加器、除法器或移位器、控制单元(状态机或时序逻辑)、以及数据通路和控制信号线。每个模块之间的连接关系,如数据输入输出、控制信号(使能、复位、时钟)都需要明确标注。</think>以下是为采样队列与平均值计算VHDL代码绘制的逻辑设计指南及实现原理说明: 一、系统架构 ``` [外部ADC] → [采样队列] → [累加器] → [除法器] → [输出寄存器] ↑ ↑ ↑ 时钟信号 → [控制单元] → 使能信号 ``` 二、核心模块分解 1. 采样队列模块(8位宽度示例) $$Q = [D7←D6←D5←D4←D3←D2←D1←D0]$$ 实现方式:8级移位寄存器链,每个时钟周期执行右移操作[^2] 2. 算术单元结构 ``` D0 D1 D2 ... D7 ↓ ↓ ↓ ↓ 加法器12位累加器 → 右移3位 → 8位输出 ``` 三、控制信号时序 1. 采样周期:CLK上升沿触发新数据移入 2. 计算周期:每8个CLK周期产生计算使能脉冲 3. 复位信号:异步清零所有寄存器和计数器 四、典型接口定义 ```vhdl entity AVG_CALC is Port ( clk : in STD_LOGIC; rst : in STD_LOGIC; data_in : in STD_LOGIC_VECTOR (7 downto 0); data_out : out STD_LOGIC_VECTOR (7 downto 0)); end AVG_CALC; ``` 五、推荐绘规范 1. 数据流:实线箭头(→) 2. 控制流:虚线箭头(⇢) 3. 寄存器:矩形框带时钟符号(▷) 4. 组合逻辑:圆角矩形
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodingW丨编程之路

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值