数据结构之树,二叉树,二叉搜索树

一.树

1.形状

2. 相关概念

节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6

叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I...等节点为叶节点

非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G...等节点为分支节点

双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点

孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点

兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点

树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6

节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;

树的高度或深度:树中节点的最大层次; 如上图:树的高度为4

堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点

节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先

子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙

森林:由m(m>0)棵互不相交的树的集合称为森林;

3.树的实现

#include <iostream>
using namespace std;//链表
template <typename T>
struct ListNode
{T data;ListNode* next;ListNode(T d):data(d),next(NULL){}
};//树的节点
template<typename T>
struct TreeNode
{T data;ListNode<TreeNode<T>*>* childHead;TreeNode() {data = T();childHead = NULL;}void addChild(TreeNode<T>* node){ListNode<TreeNode<T>*>* childNode = new ListNode<TreeNode<T>*>(node);if (childHead == NULL){childHead = childNode;}else{childNode->next = childHead;childHead = childNode;}}
};//创建树的类
template <typename T>
class Tree{
private:TreeNode<T>* nodes;TreeNode<T>* root;
public:Tree();Tree(int maxNodes);~Tree();TreeNode<T>* getTreeNode(int id);void setRoot(int rootId);void addChild(int parent,int child);void assignData(int NodeId , T data);void print(TreeNode<T>* node = NULL);
};template <typename T>
Tree<T>::Tree(){nodes = new TreeNode<T>[10000];root = NULL;
}template <typename T>
Tree<T>::Tree(int maxNodes){nodes = new TreeNode<T>[maxNodes];root = NULL;
}template <typename T>
Tree<T>::~Tree(){delete[] nodes;
}template <typename T>
TreeNode<T>* Tree<T>::getTreeNode(int id){return &nodes[id];
}template <typename T>
void Tree<T>::setRoot(int rootId){root = getTreeNode(rootId);
}template <typename T>
void Tree<T>::addChild(int parent,int child){TreeNode<T>* Parat = getTreeNode(parent);TreeNode<T>* Child = getTreeNode(child);Parat->addChild(Child);
}template <typename T>
void Tree<T>::assignData(int NodeId , T data){getTreeNode(NodeId)->data = data;
}template <typename T>
void Tree<T>::print(TreeNode<T>* node){if (node == NULL){node = root;}cout<<node->data;ListNode<TreeNode<char>*>* temp = node->childHead;while (temp){print(temp->data);temp = temp->next;}
}int main(){Tree<char> p[9];p->setRoot(0);p->assignData(0,'a');p->assignData(1,'b');p->assignData(2,'c');p->assignData(3,'d');p->assignData(4,'e');p->assignData(5,'f');p->assignData(6,'g');p->assignData(7,'h');p->assignData(8,'i');p->addChild(0,1);p->addChild(0,2);p->addChild(1,3);p->addChild(2,4);p->addChild(2,5);p->addChild(3,6);p->addChild(3,7);p->addChild(3,8);p->print();return 0;
}

二.二叉树

1.形状(最多只有两个度,也就是最多有两个节点)

2.基本概念

1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点.

2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h-1

3. 对任何一棵二叉树, 如果度为0其叶结点个数为y, 度为2的分支结点个数为x,则y=x+1

4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=log2(n+1)

3.二叉树的存储方式

1.顺序存储

        就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。

2.链式存储

        用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。

3.二叉树的遍历

  • 前序遍历

  • 中序 

  •  后续

  • 层序遍历 

  •  前,中,后序遍历的实现
    #include <iostream>
    using namespace std;//树的节点
    template<typename T>
    struct TreeNode 
    {T val;TreeNode* left;	//左子树TreeNode* right;//右子树TreeNode():val(0),left(NULL),right(NULL){};	//构造函数TreeNode(T d):val(d),left(NULL),right(NULL){};//构造函数
    };//树的类集合
    template<typename T>
    class Tree{//内置参数
    private:TreeNode<T>* nodes;	//树的节点数组	TreeNode<T>* root;	//根节点size_t nodeSize;	//节点个数TreeNode <T>* Creat(T a[],int size,int nodeId,T nullNode);	//创建树void visit(TreeNode<T>* node);	//访问节点void preOrder(TreeNode<T>* node);	//先序遍历void inOrder(TreeNode<T>* node);	//中序遍历void postOrder(TreeNode<T>* node);	//后序遍历//用于外部函数调用
    public:Tree();Tree(int maxNodes);	~Tree();	TreeNode<T>* getTreeNode (int Id);	//获取节点void CreatTree(T a[],int size,T nullNode);	//创建树void preOrder();	//先序遍历void inOrder();		//中序遍历void postOrder();	//后序遍历
    };//默认构造函数
    template<typename T>
    Tree<T>::Tree(){nodeSize = 10000;root = NULL;nodes = new TreeNode<T>[nodeSize];
    }//带参数的构造函数
    template<typename T>
    Tree<T>::Tree(int maxNodes){nodeSize = maxNodes;root = NULL;nodes = new TreeNode<T>[nodeSize];
    }//析构函数,释放内存
    template<typename T>
    Tree<T>::~Tree(){delete[] nodes;
    }//获取树节点
    template<typename T>	
    TreeNode<T>* Tree<T>::getTreeNode (int Id){return &nodes[Id];
    }//打印节点值
    template<typename T>
    void Tree<T>::visit(TreeNode<T>* node){cout<<node->val;
    }//内部创建树,递归实现
    template<typename T>
    TreeNode <T>* Tree<T>::Creat(T a[],int size,int nodeId,T nullNode){if (nodeId >= size || a[nodeId] == nullNode){return NULL;}TreeNode <T>* nowNode = getTreeNode (nodeId);nowNode->val = a[nodeId];nowNode->left = Creat(a,size,nodeId * 2,nullNode);nowNode->right = Creat(a,size,nodeId * 2 + 1,nullNode);return nowNode;
    }//外部函数创建树
    template<typename T>
    void  Tree<T>::CreatTree(T a[],int size,T nullNode){root = Creat(a,size,1,nullNode);//根节点从1开始
    }//内部实现前序遍历
    template<typename T>
    void Tree<T>::preOrder(TreeNode<T>* node){if (node){visit(node);preOrder(node->left);preOrder(node->right);}
    }//外部实现前序遍历
    template<typename T>
    void Tree<T>::preOrder(){preOrder(root);
    }//内部实现中序遍历
    template<typename T>
    void Tree<T>::inOrder(TreeNode <T>* node){if (node) {inOrder(node->left);visit(node);inOrder(node->right);}
    }//外部实现中序遍历
    template<typename T>
    void Tree<T>::inOrder(){inOrder(root);
    }//内部实现后序遍历
    template<typename T>
    void Tree<T>::postOrder(TreeNode <T>* node){if (node) {postOrder(node->left);postOrder(node->right);visit(node);}
    }//外部实现后序遍历
    template<typename T>
    void Tree<T>::postOrder(){postOrder(root);
    }int main(){const char nullNpde = '-';char a[15] = {nullNpde, 'a', 'b', 'c', 'd',nullNpde, 'e', 'f', 'g', 'h',nullNpde, nullNpde, nullNpde, nullNpde, 'i'};Tree<char> T(15);T.CreatTree(a, 15, nullNpde);T.preOrder(); cout << endl;T.inOrder(); cout << endl;T.postOrder(); cout << endl;return 0;
    }

三.二叉搜索树

 1.形状

2.概念

3.二叉树代码实现

#include <iostream>
using namespace std;//树的节点
template<typename T>
struct TreeNode
{T data;TreeNode* left;TreeNode* right;TreeNode():data(0),left(NULL),right(NULL){}TreeNode(T d):data(d),left(NULL),right(NULL){}
};template<typename T>
class BinarySearchTree{
private:TreeNode<T>* root;TreeNode<T>* insertNode(TreeNode<T>* node,T value);TreeNode<T>* removeNode(TreeNode<T>* node,T value);bool searchNode(TreeNode<T>* node,T value);void inOrder(TreeNode<T>* node);public:BinarySearchTree():root(NULL){};~BinarySearchTree();void insert(T value){root = insertNode(root,value);}void remove(T value){root = removeNode(root,value);}bool search(T value){return searchNode(root,value);}void inOrderTree(){inOrder(root);cout<<endl;}
};//析构函数,删除所有节点
template<typename T>
BinarySearchTree<T>::~BinarySearchTree(){while (root){remove(root->data);}
}//插入节点
template<typename T>
TreeNode<T>* BinarySearchTree<T>::insertNode(TreeNode<T>* node,T value){if (node == NULL){return new TreeNode<T>(value);}if (value < node->data){node->left = insertNode(node->left,value);//递归调用,直到找到合适的位置}else if(value > node->data){node->right = insertNode(node->right,value);//递归调用,直到找到合适的位置}return node;
}//删除节点
template<typename T>
TreeNode<T>* BinarySearchTree<T>::removeNode(TreeNode<T>* node,T value){if (node == NULL){return NULL;}if (value < node->data)//如果要删除的值小于当前节点的值,则递归调用左子树{node->left = removeNode(node->left,value);}else if(value > node->data)//如果要删除的值大于当前节点的值,则递归调用右子树{node->right = removeNode(node->right,value);}else//如果要删除的值等于当前节点的值{if (node->left == NULL && node->right == NULL)//如果当前节点没有子节点,则直接删除{delete node;node = NULL;return NULL;}else if(node->left == NULL)//如果当前节点没有左子节点,则用右子节点替换当前节点{TreeNode<T>* rightChild = node->right;delete node;node = rightChild;return node;}else if(node->right == NULL)//如果当前节点没有右子节点,则用左子节点替换当前节点{TreeNode<T>* leftChild = node->left;delete node;node = leftChild;return node;}else//如果当前节点有两个子节点,则用右子树中的最小节点替换当前节点{TreeNode<T>* replacement = node->right;while (replacement->left != NULL) {replacement = replacement->left;}node->data = replacement->data;node->right = removeNode(node->right, replacement->data);}}return node;
}//查找节点
template<typename T>
bool BinarySearchTree<T>::searchNode(TreeNode<T>* node,T value){if (node == NULL){return false;}if (value < node->data){return searchNode(node->left,value);}else if(value > node->data){return searchNode(node->right,value);}return true;
}//中序遍历
template<typename T>
void BinarySearchTree<T>::inOrder(TreeNode<T>* node){if (node){inOrder(node->left);cout<<node->data<<",";inOrder(node->right);}	
}int main(){BinarySearchTree<int> bst;bst.insert(10);bst.insert(30);bst.insert(20);bst.insert(40);bst.insert(60);bst.insert(50);cout<<"中序遍历"<<endl;bst.inOrderTree();cout<<"查找20:"<<bst.search(20)<<endl;cout<<"查找100:"<<bst.search(100)<<endl;bst.remove(30);bst.inOrderTree();return 0;
}

 

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

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

相关文章

LLM微调随记录

【如何把领域文献批量转换为可供模型微调的数据集&#xff1f;】 https://www.bilibili.com/video/BV1y8QpYGE57/?share_sourcecopy_web&vd_source8f9078186b93d9eee26026fd26e8a6ed 几个问题 首先要先搞清楚这几个问题 LLM 训练方法如何选择合适的训练方式如何判断是否…

高效处理大体积Excel文件的Java技术方案解析

高效处理大体积Excel文件的Java技术方案解析 引言 在数据密集型应用中&#xff0c;处理数百MB甚至GB级的Excel文件已成为业务刚需。传统基于DOM模型的Excel解析方式&#xff08;如Apache POI的XSSF&#xff09;在处理大规模数据时存在严重的内存瓶颈。本文将深入探讨Java生态中…

JVM垃圾回收机制深度解析

&#x1f5d1;️ JVM垃圾回收机制深度解析 文章目录&#x1f5d1;️ JVM垃圾回收机制深度解析&#x1f50d; 垃圾判定算法&#x1f522; 引用计数法&#x1f310; 可达性分析算法&#x1f504; 垃圾回收算法&#x1f3f7;️ 标记-清除算法&#x1f4cb; 复制算法&#x1f527; …

Docker:容器化技术的基石与实践指南

在现代软件开发和部署中&#xff0c;Docker 作为一种领先的容器化平台&#xff0c;已经成为了开发人员和运维工程师不可或缺的工具。它不仅简化了应用的部署过程&#xff0c;还提高了应用的可移植性和可扩展性。本文将深入探讨 Docker 的核心概念、基本操作以及如何在实际项目中…

java web7(黑马)

Filter简介概念: Filter 表示过滤器&#xff0c;是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。过滤器可以把对资源的请求拦截下来&#xff0c;从而实现一些特殊的功能。过滤器一般完成一些通用的操作&#xff0c;比如:权限控制、统一编码处理、敏感字符处理等等.快速入…

React-forwardRef-useImperativeHandle

forwardRef 暴露dom节点作用&#xff1a;使用ref暴露DOM节点给父组件案例例如在父组件中想要获取子组件input的输入值&#xff0c;和让input获取焦点父组件import { Button } from antd-mobile import Son from "./components/son"; import { useState,useRef } fro…

Unity 用AI自动开发游戏----Cursor研究(实现一套利用Cursor生成模板快速实现原型的框架)

Unity 快速原型开发框架&#xff08;基于 Cursor AI&#xff09; &#x1f9e9; 框架简介 本框架结合了 AI 编程助手 Cursor 的代码生成能力&#xff0c;构建出一套适用于 Unity 项目的模块化原型开发架构。它旨在极大提升开发效率、降低试错成本&#xff0c;特别适用于快速搭…

D触发器实现2分频verilog及电路

使用D触发器完成2分频电路即通过时钟的上升沿或下降沿到来时进行翻转得到&#xff0c;信号的两个状态所占时间长度相同&#xff0c;因此它的输出时钟的占空比为50%。 D触发器实现2分频的电路图如下所示&#xff1a;通过将D触发器2分频电路级联&#xff0c;可实现输入时钟的2N倍…

UniApp完美对接RuoYi框架开发企业级应用

UniApp完美对接RuoYi框架的完整方案及可开发系统类型&#xff0c;结合企业级实践与开源项目经验整理而成&#xff0c;涵盖技术对接、系统设计及实战案例。 &#x1f527; 一、UniApp与RuoYi对接全流程 1. 后端配置&#xff08;RuoYi-Vue/RuoYi-Cloud&#xff09; 跨域支持 在网…

【通识】深度学习理论基础

1. 深度学习导论 导论和简介的基础知识和路径。 深度学习的各项涵盖范围&#xff1a;深度学习MLPs&#xff0c;然后是机器学习、逻辑回归&#xff0c;知识基础等等 1&#xff09;连结神经网络等等&#xff1a;Cybernetics控制论&#xff0c;Connectionism连结主义&#xff0…

sql-labs(11-12)-万能密码登录

sql-labs(11-12)万能密码登录 第十一关&#xff1a; 这关是一个登陆口&#xff0c;也是一个sql注入的漏洞&#xff0c;也就是常说的万能密码。 在输入框账号密码种分别输入 1’ 和1’ 页面会报错。后台使用的单引符号进行的拼接。账号输入1’ or ‘1’‘1 密码输入 1’ or …

MsSql 其他(2)

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨Mysql中的MVCC 一、MVCC 的核心目标与设计背景 MVCC&#xff08;Multi-Version Concurrency Control&#xff0c;多版本并发控制&#xff09; 是 InnoDB 存储引擎为实现高并发事务处理而设计的核心机制。其核心目标是&#xff1a;在不牺牲事务隔…

解决本地部署n8n,域名访问为什么一直有connection lost的报错

问题&#xff1a;本地部署的n8n服务用IP访问一切都正常&#xff0c;但是使用域名后报错connection lost思路&#xff1a;首先怀疑是ngnix配置问题或者是docker中的环境问题查看docker logsOrigin header does NOT match the expected origin. (Origin: "nxxx.online:1181&…

传统架构开发VS PREEvision:一场效率与可靠性的降维打击

当前&#xff0c;整车功能数量激增&#xff0c;意味着需要更庞大的整车数据库、更复杂的硬件传感器与执行器网络、更密集的跨系统交互接口以及更难以预测的耦合效应。这样一来&#xff0c;单一功能的微小改动&#xff0c;可能会因复杂的依赖关系而引发意想不到的连锁反应&#…

深度学习基础1

一、张量 张量其实就是数组&#xff0c;不过是在深度学习中是这样的叫法 1.张量的创建 &#xff08;1&#xff09;基本创建方式 torch.tensor()&#xff1a;根据指定数据创建张量 import torch import numpy as np """创建张量标量""" data to…

力扣网编程274题:H指数之普通解法(中等)

一. 简介 本文记录力扣网上涉及数组&#xff0c;排序方面的编程题&#xff1a;H指数。 二. 力扣网编程274题&#xff1a;H指数&#xff08;中等&#xff09; 给你一个整数数组 citations &#xff0c;其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研…

iptables防火墙,多IP环境下, 指定某个目的IP地址通过某个本地IP访问,策略路由!

需求在CentOS 7.9中&#xff0c;若需从特定源IP&#xff08;10.0.0.3&#xff09;访问目标网段 1.1.1.0/24方法一&#xff1a;策略路由&#xff08;支持网段&#xff09;1. 创建自定义路由表# 添加名为custom_table的路由表&#xff08;ID200&#xff09; echo "200 custo…

数字孪生技术引领UI前端设计新趋势:数据可视化与交互设计的深度融合

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言&#xff1a;数字孪生驱动 UI 设计的范式革新在大数据与三维可视化技术爆发的今天&…

【机器学习笔记 Ⅱ】6 激活函数

激活函数是神经网络的核心组件&#xff0c;其作用远不止“引入非线性”。以下是系统化的解析&#xff1a;1. 核心作用 (1) 引入非线性没有激活函数&#xff1a;多层神经网络等价于单层线性变换&#xff08;矩阵连乘仍是线性&#xff09;。加入激活函数&#xff1a;每层通过非线…

AI无标记动捕如何结合VR大空间技术打造沉浸式游戏体验

随着数字科技的迅猛发展&#xff0c;VR大空间技术正逐步成为各行业探索沉浸式体验的重要方向。在VR游戏领域&#xff0c;市场对于高度沉浸式体验的需求日益增长&#xff0c;而传统VR游戏主要依赖手柄和基础体感进行交互&#xff0c;而在VR大空间中&#xff0c;用户可以通过全身…