数据结构——树(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