树的概念:树是N(N>=0)个有限数组元素的集合,形状像一棵倒过来的树
节点:节点包含数据和指向其他节点的指针,树的第一个节点称为根节点
度:节点拥有的子节点的数
树的高度:树中距离根节点最远节点的路径
二叉树:二叉树是一棵特殊的数,二叉树每个节点最多有两个孩子节点,为左孩子和有孩子。满二叉树:高度为N的慢二叉树有2*N-1个节点的二叉树
完全二叉树:若二叉树的深度为H,除第H层以外,其他各层的节点都达到最大个数,第H层的所有节点都连续集中在最左边。
二叉树的实现:
节点构造:
template <class T> struct BinaryTreeNode { BinaryTreeNode<T>* _left; BinaryTreeNode<T>* _right; T _data; BinaryTreeNode(const T& x) : _left(NULL) , _right(NULL) , _data(x) {} };
前序遍历:
前序遍历过程:a.先访问根节点b.前序访问左子树c.前序访问右子树
A.递归前序遍历:优点:代码量少,易实现。缺点:难理解,建议画图理解(与栈帧联系紧密)
void _PrevOrder(Node* root) { if (root == NULL) return; cout << root->_data << " "; _PrevOrder(root->_left); _PrevOrder(root->_right); }
先访问根节点,输出节点的值,再访问左子树,遇空返回,访问右子树。每次的递归都可以认为是访问子树的根节点并输出。
B.非递归前序遍历:利用栈的后进先出的原则,实现前序遍历。
PS:节点插入栈的顺序便是前序遍历过程。
void PrevOrderNonR() { stack<Node*> s; Node* cur = _root; while (cur || !s.empty()) { while (cur) { cout << cur->_data << " "; s.push(cur); cur = cur->_left; } Node* top = s.top(); s.pop(); cur = top->_right; } cout << endl; }
优先访问左子树,并将左子树的根节点存入栈,判断节点和栈是否为空,进行循环,输出节点的值,每当内层循环退出时,代表该子树的左子树访问完,此时取出栈顶节点,并释放栈顶,栈顶节点为该子树的根节点,此时继续外层循环,重复上述动作,实现非递归遍历。
中序遍历
中序遍历过程:a.中序访问左子树b.访问根节点c.中序访问访问右子树
A.递归中序遍历:优点:代码量少,易实现。缺点:难理解,建议画图理解(与栈帧联系紧密)
递归时传入的左孩子都可以被认为是该子树的根节点,当递归到最左节点时判空退出本次递归,输出当前节点的值,带入当前节点的右孩子,继续递归。
void _InOrder(Node* root) { if (root == NULL) return; _InOrder(root->_left); cout << root->_data << " "; _InOrder(root->_right); }
B.非递归中序遍历:利用栈的后进先出原则实现遍历。
PS:从栈顶取出数据的顺序便是中序遍历的顺序
void InOrderNonR()
{
stack<Node*> s;
Node* cur = _root;
while (cur || !s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
Node* top = s.top();
s.pop();
cout << top->_data << " ";
cur = top->_right;
}
cout << endl;
}
访问当前节点,存入栈中,判断当前节点和栈是否为空,进行循环,内层循环退出时取出栈顶,输出栈顶值,释放栈顶,设当前节点指向右孩子,进行外层循环,重复上述过程。
后序遍历
后续遍历过程:a.后序访问左子树b.后序访问右子树c.访问根节点
后序遍历过程中,根节点会被访问多次,因此递归的方法难以实现,只写出了非递归的后序遍历。
A.递归后序遍历
void _PostOrder(Node* root) { if (root == NULL) return; _PostOrder(root->_left); _PostOrder(root->_right); cout << root->_data << " "; }
原理类似前序和后序递归遍历。
B.非递归后序遍历:利用栈的后进先出原则实现遍历。
PS:非递归后序遍历难点在于,由于子树的根节点会被访问多次,因此在输出节点值和释放栈顶是应进行判断是否执行上述操作。
void PostOrder() { stack<Node*> s; Node* prev = NULL; Node* cur = _root; while (cur || !s.empty()) { while (cur) { s.push(cur); cur = cur->_left; } Node* front = s.top(); if (front->_right == NULL || front->_right == prev) { cout << front->_data << " "; prev = front; s.pop(); } else { cur = front->_right; } } cout << endl; }
设置父亲节点变量保存前次访问的节点指针,当内层循环结束时,当前节点为最左节点,再此取出栈顶并进行判断,节点右节点为空或者右节点已被访问过,便可以输出并释放栈顶,继续外层循环。
层序遍历
层序遍历过程:a.访问根节点b.访问下一层所有节点C.....
void LevelOrder() { queue<Node*> q; if (_root) q.push(_root); while (!q.empty()) { Node* front = q.front(); cout << front->_data << " "; if (front->_left) q.push(front->_left); if (front->_right) q.push(front->_right); q.pop(); } cout << endl; }
利用队列的先进先出原则实现遍历。循环开始时先取出队头,输出当前的节点值,每次根据条件,尾插入当前节点的左孩子和右孩子。循环结束时释放队列的头,以队列是否为空为循环结束的条件。
二叉树整体代码实现如下:
#pragma once #include <queue> #include <stack> using namespace std; template <class T> struct BinaryTreeNode { BinaryTreeNode<T>* _left; BinaryTreeNode<T>* _right; T _data; BinaryTreeNode(const T& x) : _left(NULL) , _right(NULL) , _data(x) {} }; template <class T> class BinaryTree { typedef BinaryTreeNode<T> Node; public: BinaryTree() : _root(NULL) {} BinaryTree(T* a, size_t n, const T& invalid) { size_t index = 0; _root = CreateTree(a, n, invalid, index); } BinaryTree(const BinaryTree<T>& t) { _root = Copy(t._root); } Node* Copy(Node* root) { if (root == NULL) return NULL; Node* newNode = new Node(root->_data); newNode->_left = Copy(root->_left); newNode->_right = Copy(root->_right); return newNode; } ~BinaryTree() { Destroy(_root); } void Destroy(Node* root) { if (root == NULL) return; Destroy(root->_left); Destroy(root->_right); delete root; } void PrevOrder() { _PrevOrder(_root); cout << endl; } void PrevOrderNonR() { stack<Node*> s; Node* cur = _root; while (cur || !s.empty()) { while (cur) { cout << cur->_data << " "; s.push(cur); cur = cur->_left; } Node* top = s.top(); s.pop(); cur = top->_right; } cout << endl; } void InOrder() { _InOrder(_root); cout << endl; } void InOrderNonR() { stack<Node*> s; Node* cur = _root; while (cur || !s.empty()) { while (cur) { s.push(cur); cur = cur->_left; } Node* top = s.top(); s.pop(); cout << top->_data << " "; cur = top->_right; } cout << endl; } void PostOrder() { _PostOrder(_root); cout << endl; } void PostOrderNonR() { stack<Node*> s; Node* prev = NULL; Node* cur = _root; while (cur || !s.empty()) { while (cur) { s.push(cur); cur = cur->_left; } Node* front = s.top(); if (front->_right == NULL || front->_right == prev) { cout << front->_data << " "; prev = front; s.pop(); } else { cur = front->_right; } } cout << endl; } //层序遍历 void LevelOrder() { queue<Node*> q; if (_root) q.push(_root); while (!q.empty()) { Node* front = q.front(); cout << front->_data << " "; if (front->_left) q.push(front->_left); if (front->_right) q.push(front->_right); q.pop(); } cout << endl; } Node* Find(const T& x) { return _Find(_root, x); } size_t Size() { return _Size(_root); } size_t LeafSize() { return _LeafSize(_root); } size_t Depth() { return _Depth(_root); } size_t KLeafSize(size_t k) { return _KLeafSize(_root, k); } protected: size_t _KLeafSize(Node* root,size_t k) { if (root == NULL) return 0; if (k == 1) return 1; return _KLeafSize(root->_left, k - 1) + _KLeafSize(root->_right, k - 1); } size_t _Depth(Node* root) { if (root == NULL) return 0; if (root->_left == NULL&&root->_right == NULL) return 1; size_t left = _Depth(root->_left); size_t right = _Depth(root->_right); return left > right ? left + 1 : right + 1; } size_t _LeafSize(Node* root) { if (root == NULL) return 0; if (root->_left == NULL && root->_right == NULL) return 1; return _LeafSize(root->_left) + _LeafSize(root->_right); } size_t _Size(Node* root) { if (root == NULL) return 0; return _Size(root->_left) + _Size(root->_right) + 1; } Node* _Find(Node* root, const T& x) { if (root == NULL) return NULL; if (root->_data == x) return root; Node* ret = _Find(root->_left, x); if (ret) return ret; return _Find(roo->_right, x); } void _PrevOrder(Node* root) { if (root == NULL) return; cout << root->_data << " "; _PrevOrder(root->_left); _PrevOrder(root->_right); } void _InOrder(Node* root) { if (root == NULL) return; _InOrder(root->_left); cout << root->_data << " "; _InOrder(root->_right); } void _PostOrder(Node* root) { if (root == NULL) return; _PostOrder(root->_left); _PostOrder(root->_right); cout << root->_data << " "; } Node* CreateTree(T* a,size_t n,const T& invalid,size_t& index) { Node* root = NULL; if (index < n && a[index] != invalid) { root = new Node(a[index]); root->_left = CreateTree(a, n, invalid, ++index); root->_right = CreateTree(a, n, invalid, ++index); } return root; } protected: Node* _root; }; void TestBinaryTreeThd() { int array[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 }; BinaryTree<int> t1(array, sizeof(array) / sizeof(array[0]), '#'); t1.PrevOrder(); //递归前序遍历 t1.PrevOrderNonR(); //非递归前序遍历 t1.InOrder(); //递归中序遍历 t1.InOrderNonR(); //非递归中序遍历 t1.PostOrder(); //递归后序遍历 t1.PostOrderNonR(); //非递归后序遍历 t1.LevelOrder(); //层序遍历 cout << t1.Size() << endl; //树的大小 cout << t1.LeafSize() << endl;//叶子大小 cout << t1.Depth() << endl; //树的深度 cout << t1.KLeafSize(3) << endl;//第3层叶子数 BinaryTree<int> t2(t1); //拷贝构造 t2.PrevOrder(); }