数据结构——树(c++实现)
2017-07-24 23:35
337 查看
树的相关概念
空树:是高度为0的合法树;单一节点:是高度为1的树(是节点既是根也是叶子的唯一情况);
极端情况下,树退化为链表;
二叉树:节点可以包含两个子节点(也可能为空)的树,每一个子节点都区分为左子节点或右子节点。
完全二叉树:所有的非终端节点都有两个子节点,所有的叶节点都位于同一层次;
对于非空二叉树,若其所有的非终端节点刚好有两个非空子节点,则叶节点的数目m大于非终端节点的数目k,并且m=k+1;
二叉查找树(有序二叉树):对于树中的每个节点n,其左子树(根节点为左子节点的树)中的值小于节点n中的值v,其右子树中的值大于节点n中的值v。
二叉树的实现
二叉树至少可以有两种方式实现:数组和链接结构。这里使用链接结构实现。二叉查找树的性质:
对于树中的每个节点X,它的左子树中所有项的值都要小于X中的项; 对于树中的每个节点Y,它的右子树中所有项的值都要大于Y中的项。
通用二叉查找树的实现
代码如下:// tree.cpp : 通用二叉查找树的实现代码 // #include "stdafx.h" #include<iostream> #include<list> #include<stack> #include<queue> using namespace std; //栈实现 template<class T> class Stack : public stack<T> { public: T pop() { T tmp = top(); stack<T>::pop(); return tmp; } }; //队列实现 template<class T> class Queue : public queue<T> { public: T dequeue() { T tmp = front(); queue<T>::pop(); return tmp; } void enqueue(const T& el) { push(el); } };
//树节点类 template<class T> class Node { public: Node():left(NULL),right(NULL){} Node(const T& e,Node<T>* l=NULL,Node<T>*r=NULL):data(e),left(l),right(r){} ~Node(){} T data; Node* left; Node* right; };
//二叉查找树的实现类 template<class T> class BST { public: BST():root(NULL){} BST(T* a, int len); //根据数组中的数据构造树,调试测试用 ~BST() { clear(); } bool isEmpty() const { return NULL == root; } void clear() { clear(root); root = NULL; } void insert(const T&); //插入 void remove(const T &x); // 删除二叉查找树中指定的值 void recursiveInsert(const T& el) { recursiveInsert(root, el); } Node<T>* search(const T& el) const { //查找 return search(root, el); } Node<T>* recursiveSearch(const T& el) const { return recursiveSearch(root, el); } void preorder() {//深度遍历之前序树遍历 preorder(root); } void inorder() {//深度遍历之中序树遍历 inorder(root); } void postorder() {//深度遍历之后序树遍历 postorder(root); } void iterativePreorder(); //深度遍历之前序树遍历 void iterativeInorder(); //深度遍历之中序树遍历 void iterativePostorder(); //深度遍历之后序树遍历 void breadthFirst(); //广度优先遍历 const T& findMin()const; // 查找最小值,并返回最小值 const T &findMax() const; // 查找最大值,并返回最大值 protected: Node<T>* root; //根节点 void clear(Node<T>*); void recursiveInsert(Node<T>*&, const T&); Node<T>* search(Node<T>*, const T&) const; Node<T>* recursiveSearch(Node<T>*, const T&) const; void preorder(Node<T>*); void inorder(Node<T>*); void postorder(Node<T>*); virtual void visit(Node<T>* p) { cout << p->data << ' '; } Node<T>* findMin(Node<T>* t) const; //迭代方式实现 Node<T>* findMax(Node<T>* t) const; //迭代方式实现 Node<T>* findMin_loop(Node<T>* t) const; //循环方式实现 Node<T>* findMax_loop(Node<T>* t) const; //循环方式实现 void remove(const T&x,Node<T>*& t) const; };
//根据数组中的内容构造树 template<class T> BST<T>::BST(T* a, int len) { root = NULL; for (int i = 0; i < len; i++) { insert(a[i]); } } //清除节点p及其子节点 template<class T> void BST<T>::clear(Node<T> *p) { if (p != NULL) { clear(p->left); clear(p->right); delete p; } } //插入 template<class T> void BST<T>::insert(const T& el) { Node<T> *p = root, *prev = NULL; while (p != NULL) { // find a place for inserting new node; prev = p; if (el < p->data) p = p->left; else p = p->right; } if (root == NULL) // tree is empty; root = new Node<T>(el); else if (el < prev->data) prev->left = new Node<T>(el); else prev->right = new Node<T>(el); } //插入,递归实现 template<class T> void BST<T>::recursiveInsert(Node<T>*& p, const T& el) { if (p == NULL) p = new Node<T>(el); else if (el < p->data) recursiveInsert(p->left, el); else recursiveInsert(p->right, el); } //查找 template<class T> Node<T>* BST<T>::search(Node<T>* p, const T& el) const { while (p != NULL) { if (el == p->data) return &p->el; else if (el < p->data) p = p->left; else p = p->right; } return NULL; } //查找,递归实现 template<class T> Node<T>* BST<T>::recursiveSearch(Node<T>* p, const T& el) const { if (p != NULL) if (el == p->data) return p; else if (el < p->data) return recursiveSearch(p->left, el); else return recursiveSearch(p->right, el); else return NULL; } template<class T> void BST<T>::remove(const T& x,Node<T>* &t) const { if(NULL==t) return; if(x<t->data) { remove(x,t->left); }else if(x>t->data) { remove(x,t->right); }else if(t->left!=NULL&&t->right!=NULL) { //拥有2个子节点 t->data=findMin(t->right)->data;//当前元素用右子树最小值填充 remove(t->data,t->right); //填充值被移走了,需要删除原填充值 }else if(t->left==NULL&&t->right==NULL) { //没有子节点,最简单的情况,直接删掉 delete t; t=NULL; }else if(t->left==NULL||t->right==NULL) { //拥有一个子节点 Node<T>* p=t; t=(t->left!=NULL)?t->left:t->right;//用其子节点占据删除掉的位置; delete p;//直接删除对应的节点 } } //删除指定元素 template<class T> void BST<T>::remove(const T& x) { remove(x,root); } //中序遍历,递归实现 template<class T> void BST<T>::inorder(Node<T> *p) { if (p != NULL) { inorder(p->left); visit(p); inorder(p->right); } } //前序遍历,递归实现 template<class T> void BST<T>::preorder(Node<T> *p) { if (p != NULL) { visit(p); preorder(p->left); preorder(p->right); } } //后续遍历,递归实现 template<class T> void BST<T>::postorder(Node<T>* p) { if (p != NULL) { postorder(p->left); postorder(p->right); visit(p); } } //广度优先遍历(从上到下,从左到右) template<class T> void BST<T>::breadthFirst() { Queue<Node<T>*> m_queue; Node<T>* p = root; if (p != NULL) { m_queue.enqueue(p); while (!m_queue.empty()) { p = m_queue.dequeue(); visit(p); if (p->left != NULL) m_queue.enqueue(p->left); else if (p->right != NULL) m_queue.enqueue(p->right); } } } //前序遍历,非递归实现 template<class T> void BST<T>::iterativePreorder() { Stack<Node<T>*> m_stack; Node<T>* p = root; if (p != NULL) { m_stack.push(p);//从跟节点开始压 while (!m_stack.empty()) { p = m_stack.pop(); visit(p); if (p->right != NULL)//先压右子节点再压左子节点,因为要左侧先出 m_stack.push(p->right); if (p->left != NULL) // left child pushed after right m_stack.push(p->left); } } } //后续遍历,非递归实现 template<class T> void BST<T>::iterativePostorder() { Stack<Node<T>*> m_stack; Node<T>* p = root, *q = root; while (p != NULL) { for (; p->left != NULL; p = p->left) m_stack.push(p); while (NULL == p->right || q == p->right) { visit(p); q = p; if (m_stack.empty()) return; p = m_stack.pop(); } m_stack.push(p); p = p->right; } } //后续遍历,非递归实现 template<class T> void BST<T>::iterativeInorder() { Stack<Node<T>*> m_stack; Node<T>* p = root; while (p != NULL) { while (p != NULL) { // stack the right child (if any) if (p->right) // and the node itself when going m_stack.push(p->right); // to the left; m_stack.push(p); p = p->left; } p = m_stack.pop(); // pop a node with no left child while (!m_stack.empty() && p->right == NULL) { // visit it and all nodes visit(p); // with no right child; p = m_stack.pop(); } visit(p); // visit also the first node with if (!m_stack.empty()) // a right child (if any); p = m_stack.pop(); else p = NULL; } }
//这段代码是实现查找最大值和最小值的代码 /*思路:我们可以从root节点开始: 一直沿着左节点往下找,直到子节点等于NULL为止,这样就可以找到最小值了; 一直沿着右节点往下找,直到子节点等于NULL为止,这样就可以找到最大值了。 */ //递归的方式 template<class T> Node<T>* BST<T>::findMin(Node<T>* t) const { if(NULL==t){ return NULL; } else if(NULL==t->left){ return t; } else{ return findMin(t->left); } } //递归的方式 template<class T> Node<T>* BST<T>::findMax(Node<T>* t) const { if(NULL==t){ return NULL; } else if(NULL==t->right){ return t; } else{ return findMax(t->right); } } //循环方式 template<class T> Node<T>* BST<T>::findMin_loop(Node<T>* t) const { if(NULL==t) { return NULL; } while(t->left) { t=t->left; } return t; } //循环方式 template<class T> Node<T>* BST<T>::findMax_loop(Node<T>* t) const { if(NULL==t) { return NULL; } while(t->right) { t=t->right; } return t; } //查找最小值,并返回最小值 template<class T> const T& BST<T>::findMin() const { Node<T>* p=findMin(root); return p->data; } //查找最大值,并返回最大值 template<class T> const T& BST<T>::findMax() const { Node<T>* p=findMax(root); return p->data; }
int main() { int a[] = { 13,10,25,2,12,20,31,29 }; BST<int> tree(a, sizeof(a) / sizeof(a[0])); cout << endl; tree.inorder(); cout << endl; tree.iterativeInorder(); system("pause"); return 0; }
代码解析
findMin和findMax实现
根据二叉查找树的性质:对于树中的每个节点X,它的左子树中所有项的值都要小于X中的项; 对于树中的每个节点Y,它的右子树中所有项的值都要大于Y中的项。
我们可以从root节点开始:
一直沿着左节点往下找,直到子节点等于NULL为止,这样就可以找到最小值了; 一直沿着右节点往下找,直到子节点等于NULL为止,这样就可以找到最大值了。
如下图所示:
remove实现
remove函数用来删除二叉查找树中指定的元素值。在删除子节点时,需要分以下几种情况进行考虑:1. 需要删除的子节点,它没有任何子节点;例如图中的节点9、节点17、节点21、节点56和节点88;这些节点它们都没有子节点;
2. 需要删除的子节点,只有一个子节点(只有左子节点或右子节点);例如图中的节点16和节点40;这些节点它们都只有一个子节点;
3. 需要删除的子节点,同时拥有两个子节点;例如图中的节点66等。
1. 对于情况1,直接删除对应的节点即可;实现起来时比较简单的;
2. 对于情况2,直接删除对应的节点,然后用其子节点占据删除掉的位置;
3. 对于情况3,是比较复杂的。首先在需要被删除节点的右子树中找到最小值节点,然后使用该最小值替换需要删除节点的值,然后在右子树中删除该最小值节点。
参考资料
http://www.jellythink.com/archives/692
相关文章推荐
- 程序员面试宝典之数据结构基础----C++两个栈实现一个队列功能
- 数据结构之顺序表C++实现
- 数据结构(5) 链栈 c++ 模板实现
- 数据结构(3)单循环链表 c++ 模板实现
- C++数据结构与STL--双向循环链表(实现自定义iterator类)
- 数据结构单项链表C++实现改变C版本
- 软件设计师教程 数据结构之循环队列的实现 (C/C++语言)
- 数据结构,图的邻接矩阵创建,邻接矩阵与邻接表的交换,两种表的输出,过程用C++实现
- C/C++用匿名数据结构实现时间和空间名利双收
- C/C++用匿名数据结构实现时间和空间名利双收
- C++和python利用struct结构传输二进制数据实现
- C++中实现通用数据结构
- 数据结构之链表的实现-------C++课程设计-----学生选课管理系统
- C++数据结构——二叉搜索树迭代器的实现
- 数据结构(2)单链表 c++ 模板实现
- C++中实现通用数据结构(转)
- 数据结构之单链表(C++实现)
- C++数据结构——二叉搜索树(实现自定义迭代器)
- 数据结构之双向循环链表(C++实现)
- 数据结构(4) 顺序栈 c++ 模板实现