二叉树的实现

来源:互联网 发布:天刀神威捏脸数据 编辑:程序博客网 时间:2024/06/04 01:18

树的概念:树是NN>=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();}