二叉树
来源:互联网 发布:如何当淘宝模特 编辑:程序博客网 时间:2024/06/04 17:58
二叉树:
是由N个结点组成的有限集合,该集合可为空(空二叉树),或者由一个根节点和两个互不相交的子节点组成。
二叉树的特点:
1) 最多有两棵子树,所以二叉树中不存在度大于2的结点;
2) 左子树和右子树是有序的,不可随意改变;
3) 五种基本形态:
A. 空二叉树;
B. 只有一个根节点的二叉树;
C. 根节点只有左子树;
D. 根节点只有右子树;
E. 根节点既有左子树又有右子树;
(树不能带环,子节点不能拥有多个父节点;)
特殊的二叉树:
1) 满二叉树:
在一颗二叉树中,所有的分支节点都存在左子树和右子树,并且所有的叶子都在同一层上,这样的二叉树称为满二叉树;
2) 完全二叉树:
对一棵有N个结点的二叉树按照层序编号,如果编号为i的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,这样的二叉树称为完全二叉树。(说白了其实就是将结点层序遍历存放在数组中,结点之间没有空缺。)
3) 斜树;
所有结点都在左子树的二叉树为左斜树;
所有结点都在右子树的二叉树为右斜树;
二者统称为斜树;
二叉树的表示方法:
1. 数组表示:
缺点:浪费空间,对于没有孩子的也要占用空间,只适用于完全二叉树和满二叉树;
2. 链表表示:
A. 二叉链表:有左孩子,右孩子
B. 三叉链表:有左孩子,右孩子,父节点
遍历方式:
A. 前序遍历:根结点—》左孩子—》右孩子
B. 中序遍历:左孩子—》根节点—》右孩子
C. 后序遍历:左孩子—》右孩子—》根节点
代码表示三种遍历方式:
递归遍历:
//三种遍历方式 void printfTreePrev(Node* root)//打印tree,使用前序----根左右 { if(root == NULL) return; cout<<root->_data<<" "; printfTreePrev(root->_leftChild); printfTreePrev(root->_rightChild); } void printfTreeMid(Node* root)//打印tree,使用中序----左根右 { if(root == NULL) return ; printfTreeMid(root->_leftChild); cout<<root->_data<<" "; printfTreeMid(root->_rightChild); } void printfTreeBack(Node* root)//打印tree,使用后序----左右根 { if(NULL == root) return; printfTreeBack(root->_leftChild); printfTreeBack(root->_rightChild); cout<<root->_data<<" "; }
非递归遍历:
思想:这里以前序遍历为主我们简单分析一下:
判断当前节点(当前节点就是此时栈顶元素,此时还没有pop出来)的左子树是否有?有就pushback()当前节点的左孩子,没有就popback(),读取栈顶元素,并且访问其右子树,if右子树有,就pushback()当前节点的右孩子,然后再判断右孩子是否有左子树,有就pushback(),就这样一直循环该思想,就是下图这样的行走方式,
//采用非递归的方式---利用栈的后进先出的思想--- //先访问根节点,访问完了以后就push,然后访问左子树,直到访问的左子树为NULL,然后就pop取出栈顶元素访问其右子树,以此类推 //先序遍历----根左右 void PreOrder() { vector<Node*> v; cout<<"中序遍历:"<<endl; Node* cur = _root; while(cur || !v.empty()) { while(cur) { v.push_back(cur); cout<<cur->_data<<" "; cur = cur->_leftChild; } Node* top = v.back(); cur = top->_rightChild; v.pop_back(); } cout<<endl; } //中序遍历----左根右 void MidOrder() { vector<Node*> v; cout<<"中序遍历:"<<endl; Node* cur = _root; while(cur || !v.empty()) { while(cur) { v.push_back(cur); cur = cur->_leftChild; } Node* top = v.back(); cout<<top->_data<<" "; cur = top->_rightChild; v.pop_back(); } cout<<endl; } //后序遍历----左右根 void BackOrder() { vector<Node*> v; cout<<"后序遍历:"<<endl; Node* cur = _root; Node* pre = NULL; while(cur || !v.empty()) { while(cur) { v.push_back(cur); cur = cur->_leftChild; } Node* top = v.back(); if(top->_rightChild == NULL || top->_rightChild == pre) { cout<<top->_data<<" "; pre = top; v.pop_back(); } else { cur = top->_rightChild; } } cout<<endl; }
二叉树代码补充完整:
template <class T>struct TreeNode{ T _data; TreeNode<T>* _leftChild; TreeNode<T>* _rightChild; TreeNode(const T& data) :_data(data),_leftChild(NULL),_rightChild(NULL) {}};template <class T>class BinaryTree{ typedef TreeNode<T> Node;protected: Node* _root;public: BinaryTree() :_root(NULL) {} BinaryTree(T* arr, size_t n, const T& invalid) { int a = 0; _root = CreateTree(arr, n, invalid, a); } ~BinaryTree()//析构函数 { Destory(_root); } //采用递归的方式 //销毁结点 void Destory(Node* root)//删除节点采用后序的遍历方式----左右根 { if(root == NULL) return; Destory(root->_leftChild); Destory(root->_rightChild); delete root; } //创建一颗树 Node* CreateTree(T* arr, size_t n, const T& invalid, int& index) { assert(arr); Node* root = NULL; if(index < n && arr[index] != invalid) { root = new Node(arr[index]); root->_leftChild = CreateTree(arr, n, invalid, ++index); root->_rightChild = CreateTree(arr, n, invalid, ++index); } return root; } //计算叶子节点的个数=======左 + 右 size_t CountLeaf() { return _CountLeaf(_root); } size_t _CountLeaf(Node* root) { if(NULL == root) { return 0; } if(root->_leftChild == NULL && root->_rightChild == NULL) return 1; return _CountLeaf(root->_leftChild) + _CountLeaf(root->_rightChild); } //计算第K层的结点个数 size_t CountKLeaf(size_t k) { return _CountKLeaf(_root,k); } size_t _CountKLeaf(Node* root, size_t k) { assert(k > 0); if(NULL == root) return 0; if(k == 1) return 1; return _CountKLeaf(root->_leftChild, k-1) + _CountKLeaf(root->_rightChild, k-1);//切勿使用--k,因为此时k是在同一层的左右子树 } //求tree的深度-----树的高度 size_t HeightTree() { return _HeightTree(_root); } size_t _HeightTree(Node* root) { if(NULL == root) return 0; size_t left = _HeightTree(root->_leftChild) + 1; size_t right = _HeightTree(root->_rightChild) + 1; return left > right ? left : right; } //找到某个节点 void Find(const T& data) { Node* node = _Find(_root,data); if(NULL == node) cout<<"find number: NULL"<<endl; else cout<<"find number: "<<node->_data<<endl; } Node* _Find(Node* root,const T& data) { if(NULL == root) return NULL; if(root->_data == data) return root; Node* left = _Find(root->_leftChild,data); if(left) return left; return _Find(root->_rightChild,data); }