数据结构——树(c++实现)
来源:互联网 发布:40不惑50知天命 编辑:程序博客网 时间:2024/06/07 07:24
树的相关概念
- 空树:是高度为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
阅读全文
0 0
- 数据结构—二叉树(C语言实现)
- 数据结构C语言实现系列[7]——二叉树
- 数据结构C语言实现系列[8]——树
- 数据结构C语言实现系列——二叉树
- 数据结构C语言实现系列——二叉树[转]
- 数据结构C语言实现系列——二叉树
- 数据结构——二叉查找树的详细实现(c++)
- 数据结构(二)——链表(C语言实现)
- 数据结构(三)——栈(C语言实现)
- 数据结构(四)——队列(C语言实现)
- 数据结构——链栈的实现(C语言)
- 数据结构——队列的链式实现(C语言)
- 数据结构——顺序表实现(c语言)
- 数据结构——顺序表(C语言实现)
- 数据结构——单链表(C语言实现)
- 【数据结构】数据结构C语言的实现(简单二叉树)
- 数据结构——单链表(C语言实现)
- 数据结构——链表C/C++实现
- 单调栈 51Nod1102
- 【Light OJ 1138 】Trailing Zeroes (III) 【二分+数学】
- (转)美国国家科学院院士张首晟演讲全文:人工智能的三大发展支柱
- 推荐一个中老年健康网和癌症知识介绍网站
- 题目1020:最小长方形
- 数据结构——树(c++实现)
- Android Things:树莓派3上手就是这么简单
- [日常折腾](四)SS+Proxifier实现全局代理/校园网免流
- 中国互联网的“去中心化”与“中心化”之战
- ubuntu17安装mysql5.7
- 算法<基于三路划分的快速排序>
- 数据结构复习—线性表的链式表示
- HDU-1978-How many ways
- spark 发布 2.2.0版本