当前位置: 首页 > news >正文

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

一.树

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.lryc.cn/news/581874.html

相关文章:

  • Chatbox➕知识库➕Mcp = 机器学习私人语音助手
  • C++ --- list的简单实现
  • 当“漏洞”成为双刃剑——合法披露与非法交易的生死线在哪里?
  • javaweb———html
  • 系统性红斑狼疮治疗靶点CD303
  • 1. http 有哪些版本,你是用的哪个版本,怎么查看
  • 在Ubuntu主机中修改ARM Linux开发板的根文件系统
  • RSTP 拓扑收敛机制
  • IRF堆叠技术的主要优势
  • 操作系统王道考研习题
  • HCIA-生成数协议(STP)
  • uniapp实现的多种时间线模板
  • DolphinScheduler 3.2.0 后端开发环境搭建指南
  • Vue计算属性(computed)全面解析:原理、用法与最佳实践
  • 多级缓存如何应用
  • C++高频知识点(二)
  • 【Pyhton】文件读取:读取整个(大型)文件
  • 铸造软件交付的“自动驾驶”系统——AI大模型如何引爆DevOps革命
  • mybatis-plus从入门到入土(二):单元测试
  • 深度学习图像分类数据集—蘑菇识别分类
  • 利用近距离全景图像进行树状结构骨架化
  • 每天一个前端小知识 Day 23 - PWA 渐进式 Web 应用开发
  • Linux国产与国外进度对垒
  • 如何使用xmind编写测试用例
  • 408第三季part2 - 计算机网络 - 应用层
  • 大数据Hadoop之——Flink1.17.0安装与使用(非常详细)
  • 分布式会话的演进和最佳实践,含springBoot 实现(Java版本)
  • 深度学习图像分类数据集—濒危动物识别分类
  • 李宏毅genai笔记:推理
  • Web攻防-XMLXXE上传解析文件预览接口服务白盒审计应用功能SRC报告