二叉树
1.二叉树的结构
顺序表 ->查找快,新增删除慢;
链表 ->查找慢,新增删除快;
二叉树 ->查找、新增、删除都比较快;
二叉树结构:
满二叉树:所有的节点都是有数据的
完全二叉树:从右往左看,右边的元素可以不满,左边的元素必须是满的
二叉树的一些常用概念:
根节点 ->第一个元素就是根节点,例如上图中的节点1;
父节点 ->相对于子节点来说的,例如上图中1是2的父节点,2是的父节点;
子节点 ->与父节点相反;
左子树 ->如果一个节点下面没有子节点,该节点叫叶子;
->父节点下面的子节点可能是叶子节点,也可能是树;
->二叉树的父节点最多有2个子节点;
->左边的子节点称为左子树;
右子树 ->父节点右边的子节点称为右子树;
2.二叉树的高度
二叉树的层级数称为高度;
例如:下图中以a为根节点二叉树高度为5;
以b为根节点二叉树高度为4;
3.二叉树的遍历
二叉树有3中常用的遍历方式:
1】前序遍历:(根 左 右)
对上图中的树遍历结果:GDAFEMHZ
2】中序遍历:(左 根 右)
结果:ADEFGHMZ
3】后序遍历:(左 右 根)
结果:AEFDHZMG
4.区分二叉树和双向链表
二叉树和双向链表的反汇编结果类似;都是一大堆数据,然后有2个地址;
追踪到地址处又是相同的结构:一堆数据其中有2个地址;
也有可能是一堆数据,有3个地址的结构,如果是这样一定是二叉树,3个地址分别为左子树、右子树、父节点;
5.练习三种遍历
中序遍历的思路:
拿上面的图来分析;
中序遍历规则为输出顺序:左 根 右
然后从下往上将拆解的子树替换,得到遍历顺序;
例如:用GDH替换左子树1,得到顺序GDHBE,然后用GDHBE替换左子树,得到顺序GDHBEA右子树;
头文件:
#ifndef TREENODE_H #define TREENODE_H #include "stdio.h" #include "stdlib.h" #include "windows.h" class Monster { public: int ID; int Level; char Name[20]; public: Monster(){} Monster(int ID,int Level,char* Name) { this->ID = ID; this->Level = Level; memcpy(&this->Name,Name,strlen(Name)+1); } }; template<class T> class TreeNode{ public: T element; //当前节点存储的数据 TreeNode<T>* pLeft; //指向左子节点的指针 TreeNode<T>* pRight; //指向右子节点的指针 TreeNode(T& ele){ //初始化Node节点 memset(&element,0,sizeof(TreeNode)); //为元素赋值 memcpy(&element,&ele,sizeof(T)); pLeft = pRight = NULL; } }; template<class T> class BSortTree{ public: BSortTree(); //构造函数 ~BSortTree(); //析构函数 public: void InOrderTraverse(TreeNode<T>* pNode); //中序遍历 void PreOrderTraverse(TreeNode<T>* pNode); //前序遍历 void PostOrderTraverse(TreeNode<T>* pNode); //后序遍历 TreeNode<T>* GetRoot(); //返回根节点 int GetDepth(TreeNode<T>* pNode); //返回某个节点的高度/深度 private: void Init(); void Clear(TreeNode<T>* pNode); private: TreeNode<T>* m_pRoot; //根结点指针 int size; //树中元素总个数 }; template<class T> BSortTree<T>::BSortTree() { Init(); } template<class T> BSortTree<T>::~BSortTree(){ //释放所以节点空间 Clear(m_pRoot); } template<class T> void BSortTree<T>::Init() { Monster m1(1,1,"刺猬"); Monster m2(2,2,"野狼"); Monster m3(3,3,"野猪"); Monster m4(4,4,"士兵"); Monster m5(5,5,"火龙"); Monster m6(6,6,"独角兽"); Monster m7(7,7,"江湖大盗"); TreeNode<Monster>* n1 = new TreeNode<Monster>(m1); TreeNode<Monster>* n2 = new TreeNode<Monster>(m2); TreeNode<Monster>* n3 = new TreeNode<Monster>(m3); TreeNode<Monster>* n4 = new TreeNode<Monster>(m4); TreeNode<Monster>* n5 = new TreeNode<Monster>(m5); TreeNode<Monster>* n6 = new TreeNode<Monster>(m6); TreeNode<Monster>* n7 = new TreeNode<Monster>(m7); m_pRoot = n5; n5->pLeft = n4; n5->pRight = n6; n4->pLeft = n1; n1->pRight = n2; n6->pLeft = n3; n3->pRight = n7; size = 7; /* 5 / \ 4 6 / / 1 3 \ \ 2 7 */ } //删除节点 template<class T> void BSortTree<T>::Clear(TreeNode<T>* pNode){ if(pNode != NULL){ Clear(pNode->pLeft); Clear(pNode->pRight); delete pNode; pNode = NULL; } } template<class T> TreeNode<T>* BSortTree<T>::GetRoot() { return m_pRoot; } template<class T> int BSortTree<T>::GetDepth(TreeNode<T>* pNode) { if(pNode==NULL) { return 0; } else { int m = GetDepth(pNode->pLeft); int n = GetDepth(pNode->pRight); return (m > n) ? (m+1) : (n+1); } } //中序遍历所有怪物,列出怪的名字 template<class T> void BSortTree<T>::InOrderTraverse(TreeNode<T>* pNode) { if(pNode != NULL){ InOrderTraverse(pNode->pLeft); printf("%d:%s\t",*(int*)(&(pNode->element)),(char*)((int)(&(pNode->element))+8)); //用指针强转的方式读取结构中的值 InOrderTraverse(pNode->pRight); } } //前序遍历所有怪物,列出怪的名字 template<class T> void BSortTree<T>::PreOrderTraverse(TreeNode<T>* pNode) { if(pNode!=NULL) { printf("%d:%s\t",pNode->element.ID,pNode->element.Name); PreOrderTraverse(pNode->pLeft); PreOrderTraverse(pNode->pRight); } } //后序遍历所有怪物,列出怪的名字 template<class T> void BSortTree<T>::PostOrderTraverse(TreeNode<T>* pNode) { if(pNode != NULL){ PostOrderTraverse(pNode->pLeft); PostOrderTraverse(pNode->pRight); printf("%d:%s\t",pNode->element.ID,pNode->element.Name); } } #endif
测试:
#include "TreeNode.h" void main(){ BSortTree<Monster>* tree = new BSortTree<Monster>; //前序遍历 printf("前序遍历\n"); tree ->PreOrderTraverse(tree->GetRoot()); printf("\n"); //后序遍历 printf("后序遍历\n"); tree ->PostOrderTraverse(tree->GetRoot()); printf("\n"); //中序遍历 printf("中序遍历\n"); tree ->InOrderTraverse(tree->GetRoot()); printf("\n"); getchar(); }
结果: