zoukankan      html  css  js  c++  java
  • 二叉树

     【数据机构和算法】章节中的【二叉树】,一直都觉得比较难。

      使用C++语言用类进行了封装,以便于今后学习!

     

      首先,定义了二叉树的节点类

    View Code
    // BinaryTreeNode.h: interface for the BinaryTreeNode class.
    // 二叉树的节点 NODE
    // 节点 、 左节点 、右节点
    // 2011-12-13 chen ang
    //////////////////////////////////////////////////////////////////////

    #if !defined(AFX_BINARYTREENODE_H__C6FD71B8_0809_43C0_B6C3_E6B7B5B032D2__INCLUDED_)
    #define AFX_BINARYTREENODE_H__C6FD71B8_0809_43C0_B6C3_E6B7B5B032D2__INCLUDED_

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000

    template<class T>
    class BinaryTreeNode
    {
    private:
    T m_element; //节点数据域
    BinaryTreeNode<T>* m_pLeft; //左节点指针
    BinaryTreeNode<T>* m_pRight; //右节点指针
    BinaryTreeNode<T>* m_pParent; //父节点指针:使用三叉链表存储
    public:
    //默认的构造函数
    BinaryTreeNode()
    {
    memset(&m_element, 0, sizeof(T));
    m_pLeft = NULL;
    m_pRight = NULL;
    m_pParent = NULL;
    };
    //析构函数
    virtual ~BinaryTreeNode(){};
    //传参的构造函数:二叉链表
    BinaryTreeNode(const T& element, BinaryTreeNode<T>* l=NULL, BinaryTreeNode<T>* r=NULL)
    {
    m_element = element;
    m_pLeft = l;
    m_pRight = r;
    m_pParent = NULL;
    };
    //传参的构造函数:三叉链表
    BinaryTreeNode(const T& element, BinaryTreeNode<T>* p, BinaryTreeNode<T>* l=NULL, BinaryTreeNode<T>* r=NULL)
    {
    m_element = element;
    m_pLeft = l;
    m_pRight = r;
    m_pParent = p;
    };
    //设置节点内容
    void SetValue(const T& element)
    {
    m_element = element;
    };
    //设置左节点指针
    void SetLeftChild(BinaryTreeNode<T>* l)
    {
    m_pLeft = l;
    };
    //设置右节点指针
    void SetRightChild(BinaryTreeNode<T>* r)
    {
    m_pRight = r;
    };
    //设置父节点指针
    void SetParent(BinaryTreeNode<T>* p)
    {
    if (NULL == m_pParent)
    {
    m_pParent = p;
    }
    };
    //获取节点内容
    T GetValue() const
    {
    return m_element;
    };
    //获取节点内容
    void DisplayValue() const
    {
    cout<<GetValue()<<" ";
    };
    //获取左节点指针
    BinaryTreeNode<T>* GetLeftChild() const
    {
    return m_pLeft;
    };
    //获取右节点指针
    BinaryTreeNode<T>* GetRightChild() const
    {
    return m_pRight;
    };
    //获取父节点指针
    BinaryTreeNode<T>* GetParent() const
    {
    return m_pParent;
    };
    //重载赋值函数
    BinaryTreeNode<T>& operator=(const BinaryTreeNode<T>& node)
    {
    m_element = node.m_element;
    m_pLeft = node.m_pLeft;
    m_pRight = node.m_pRight;
    m_pParent = node.m_pParent;
    };
    //判断当前节点是否为叶节点:是则返回true, 否则返回false
    bool IsLeaf() const
    {
    if ((NULL == m_pLeft) && (NULL == m_pRight))
    {
    return true;
    }
    else
    {
    return false;
    };
    };
    };

    #endif // !defined(AFX_BINARYTREENODE_H__C6FD71B8_0809_43C0_B6C3_E6B7B5B032D2__INCLUDED_)


      其次:定义和实现了二叉树

    View Code
    // BinaryTree.h: interface for the BinaryTree class.
    // 二叉树
    // 2011-12-13 chen ang
    //////////////////////////////////////////////////////////////////////

    #if !defined(AFX_BINARYTREE_H__E94D44AE_ADCE_4F3E_A731_699E58A76F6C__INCLUDED_)
    #define AFX_BINARYTREE_H__E94D44AE_ADCE_4F3E_A731_699E58A76F6C__INCLUDED_

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000

    #include <stack>
    #include "BinaryTreeNode.h"

    template<class T>
    class BinaryTree
    {
    private:
    BinaryTreeNode<T>* m_root; //二叉树的根节点
    public:
    //默认的构造函数
    BinaryTree()
    {
    //默认为空树
    m_root = NULL;
    };
    //传参的构造函数
    BinaryTree(const T& element)
    {
    //只有根节点一个节点的树
    m_root = new BinaryTreeNode<T>(element);
    };
    //析构函数
    virtual ~BinaryTree(){};
    //判断二叉树是否为空:空返回true; 非空返回false.
    bool IsEmpty() const
    {
    if (NULL == m_root)
    {
    return true;
    }
    else
    {
    return false;
    }
    };
    //返回二叉树的根节点
    BinaryTreeNode<T>* GetRoot() const
    {
    return m_root;
    };
    //返回current结点的父结点
    BinaryTreeNode<T>* GetParent(BinaryTreeNode<T>* current)
    {
    if ((NULL == current) || (m_root == current))
    {
    return NULL;
    }

    stack<BinaryTreeNode<T>*> s_t;
    BinaryTreeNode<T>* temp = m_root;
    while(!s_t.empty() || temp)
    {
    if (temp)
    {
    s_t.push(temp);
    if (temp->GetLeftChild() == current || temp->GetRightChild() == current)
    {
    return temp;
    }
    temp = temp->GetLeftChild();
    }
    else
    {
    temp = s_t.top();
    s_t.pop();
    temp = temp->GetRightChild();
    }
    }

    return NULL;
    };
    //返回current结点的左兄弟结点
    BinaryTreeNode<T>* GetLeftSibling(BinaryTreeNode<T>* current)
    {
    if (current)
    {
    BinaryTreeNode<T>* temp = GetParent(current);
    if ((NULL == temp) || (current == temp->GetLeftChild()))
    {
    return NULL;
    }
    else
    {
    return temp->GetLeftChild();
    }
    }
    else
    {
    return NULL;
    }
    };
    //返回current结点的右兄弟结点
    BinaryTreeNode<T>* GetRightSibling(BinaryTreeNode<T>* current)
    {
    if (current)
    {
    BinaryTreeNode<T>* temp = GetParent(current);
    if ((NULL == temp) || (current == temp->GetRightChild()))
    {
    return NULL;
    }
    else
    {
    return temp->GetRightChild();
    }
    }
    else
    {
    return NULL;
    }
    };
    //打印节点数据
    void DisplayValue(BinaryTreeNode<T>* node)
    {
    if (node)
    {
    cout<<"值等于"<<node->GetValue()<<endl;
    }
    else
    {
    cout<<"该节点为NULL!"<<endl;
    }
    }
    //概念: “周游”--系统地访问数据结构中的结点。每个结点都正好被访问到一次
    //二叉树的遍历:前序周游二叉树或其子树
    //二叉树抽象为以下共性: 所有二叉树都由【根节点或者子树的根节点】、 【左子树】、 【右子树】组成
    void PreOrder(BinaryTreeNode<T>* root)
    {
    //方法一:深度优先周游二叉树 (使用递归)
    if (NULL != root)
    {
    root->DisplayValue(); //访问【根节点或者子树的根节点】
    PreOrder(root->GetLeftChild()); //访问【根节点或者子树的根节点】的左节点
    PreOrder(root->GetRightChild()); //访问【根节点或者子树的根节点】的右节点
    }
    };
    void PreOrderInStack(BinaryTreeNode<T>* root)
    {
    //方法二:非递归深度优先周游二叉树
    // 栈是实现递归的最常用的结构
    // 利用一个栈来记下尚待周游的结点或子树,以备以后访问。
    stack<BinaryTreeNode<T>*> s_t;
    BinaryTreeNode<T>* temp = root;
    while (!s_t.empty() || temp)
    {
    if (temp)
    {
    temp->DisplayValue(); //访问【根节点或者子树的根节点】
    s_t.push(temp); // 【根节点或者子树的根节点】入栈
    temp = temp->GetLeftChild(); //转到【根节点或者子树的根节点】的左节点
    }
    else
    {
    temp = s_t.top(); //回到【根节点或者子树的根节点】
    s_t.pop(); // 【根节点或者子树的根节点】弹出栈
    temp = temp->GetRightChild(); //转到【根节点或者子树的根节点】的右节点
    }
    }
    }
    void PreOrderInStack1(BinaryTreeNode<T>* root)
    {
    //方法二:非递归深度优先周游二叉树
    // 栈是实现递归的最常用的结构
    // 利用一个栈来记下尚待周游的结点或子树,以备以后访问。
    stack<BinaryTreeNode<T>*> s_t;
    s_t.push(NULL);

    BinaryTreeNode<T>* temp = root;
    while(temp)
    {
    temp->DisplayValue();
    if (temp->GetRightChild())
    {
    s_t.push(temp->GetRightChild());
    }
    if (temp->GetLeftChild())
    {
    temp = temp->GetLeftChild();
    }
    else
    {
    temp = s_t.top();
    s_t.pop();
    }
    }
    }

    //二叉树的遍历:中序周游二叉树或其子树
    void InOrder(BinaryTreeNode<T>* root)
    {
    //方法一:深度优先周游二叉树 (使用递归)
    if (NULL != root)
    {
    InOrder(root->GetLeftChild()); //访问【根节点或者子树的根节点】的左节点
    root->DisplayValue(); //访问【根节点或者子树的根节点】
    InOrder(root->GetRightChild()); //访问【根节点或者子树的根节点】的右节点
    }
    };
    void InOrderInStack(BinaryTreeNode<T>* root)
    {
    //方法二:非递归深度优先周游二叉树
    // 栈是实现递归的最常用的结构
    // 利用一个栈来记下尚待周游的结点或子树,以备以后访问。
    stack<BinaryTreeNode<T>*> s_t;
    BinaryTreeNode<T>* temp = root;
    while (!s_t.empty() || temp)
    {
    if (temp)
    {
    s_t.push(temp); // 【根节点或者子树的根节点】入栈
    temp = temp->GetLeftChild(); //转到【根节点或者子树的根节点】的左节点
    }
    else
    {
    temp = s_t.top(); //回到【根节点或者子树的根节点】
    s_t.pop(); // 【根节点或者子树的根节点】弹出栈
    temp->DisplayValue(); //访问【根节点或者子树的根节点】的左节点
    temp = temp->GetRightChild(); //转到【根节点或者子树的根节点】的右节点
    }
    }
    }

    //二叉树的遍历:后序周游二叉树或其子树
    void PostOrder(BinaryTreeNode<T>* root)
    {
    //方法一:深度优先周游二叉树 (使用递归)
    if (NULL != root)
    {
    PostOrder(root->GetLeftChild()); //访问【根节点或者子树的根节点】的左节点
    PostOrder(root->GetRightChild()); //访问【根节点或者子树的根节点】的右节点
    root->DisplayValue(); //访问【根节点或者子树的根节点】
    }
    };
    void PostOrderInStack(BinaryTreeNode<T>* root)
    {
    //方法二:非递归深度优先周游二叉树
    // 栈是实现递归的最常用的结构
    // 利用一个栈来记下尚待周游的结点或子树,以备以后访问。
    cout<<"NULL"<<endl;
    }

    //二叉树的遍历:按层次周游二叉树或其子树
    void LevelOrder(BinaryTreeNode<T>* root)
    {
    // 使用队列
    deque<BinaryTreeNode<T>*> d_t;
    BinaryTreeNode<T>* temp;

    if (NULL != root)
    {
    d_t.push_back(root); // 【根节点或者子树的根节点】入队列尾部
    }

    while(!d_t.empty())
    {
    temp = d_t.front(); // 【根节点或者子树的根节点】
    d_t.pop_front(); // 【根节点或者子树的根节点】出队列前端
    temp->DisplayValue(); //访问【根节点或者子树的根节点】

    if (temp->GetLeftChild())
    {
    d_t.push_back(temp->GetLeftChild());// 【根节点或者子树的根节点】的左节点入队列
    }

    if (temp->GetRightChild())
    {
    d_t.push_back(temp->GetRightChild());// 【根节点或者子树的根节点】的右节点入队列
    }
    } // end while
    };

    //删除二叉树或其子树
    void DeleteBinaryTree(BinaryTreeNode<T>* root)
    {
    //后序周游二叉树或其子树
    if (root)
    {
    DeleteBinaryTree(root->GetLeftChild()); //递归删除二叉树的左子树
    DeleteBinaryTree(root->GetRightChild()); //递归删除二叉树的右子树
    delete root; //删除根节点
    root = NULL;
    }
    };
    };

    #endif // !defined(AFX_BINARYTREE_H__E94D44AE_ADCE_4F3E_A731_699E58A76F6C__INCLUDED_)


      最后,就是对二叉树进行数据录入,测试。

    // 二叉树.cpp : Defines the entry point for the console application.
    //

    #include "stdafx.h"
    #include <iostream>

    #include "BinaryTree.h"

    using namespace std;

    int main(int argc, char* argv[])
    {
    //创建一个二叉树
    BinaryTree<int> bTree(0);

    //判断是否为空
    if (bTree.IsEmpty())
    {
    cout<<"binary tree is empty"<<endl;
    }
    else
    {
    cout<<"binary tree is not empty"<<endl;
    }

    //二叉树中插入节点
    BinaryTreeNode<int>* pNode;
    //新建节点
    pNode = new BinaryTreeNode<int>(1);
    bTree.GetRoot()->SetLeftChild(pNode);
    pNode = new BinaryTreeNode<int>(2);
    bTree.GetRoot()->SetRightChild(pNode);
    pNode = new BinaryTreeNode<int>(3);
    (bTree.GetRoot()->GetLeftChild())->SetLeftChild(pNode);
    pNode = new BinaryTreeNode<int>(4);
    (bTree.GetRoot()->GetLeftChild())->SetRightChild(pNode);
    pNode = new BinaryTreeNode<int>(5);
    (bTree.GetRoot()->GetRightChild())->SetLeftChild(pNode);
    pNode = new BinaryTreeNode<int>(6);
    (bTree.GetRoot()->GetRightChild())->SetRightChild(pNode);
    //先序遍历
    cout<<endl<<"先序遍历:";
    bTree.PreOrder(bTree.GetRoot());
    cout<<endl<<"先序遍历(栈):";
    bTree.PreOrderInStack(bTree.GetRoot());
    //中序遍历
    cout<<endl<<"中序遍历:";
    bTree.InOrder(bTree.GetRoot());
    cout<<endl<<"中序遍历(栈):";
    bTree.InOrderInStack(bTree.GetRoot());
    //后序遍历
    cout<<endl<<"后序遍历:";
    bTree.PostOrder(bTree.GetRoot());

    //层次遍历
    cout<<endl<<"层次遍历:";
    bTree.LevelOrder(bTree.GetRoot());
    //获取父节点
    cout<<endl<<"获取父节点:";
    bTree.DisplayValue(bTree.GetParent(pNode));
    cout<<"获取左节点:";
    bTree.DisplayValue(bTree.GetLeftSibling(pNode));
    cout<<"获取右节点:";
    bTree.DisplayValue(bTree.GetRightSibling(pNode));
    //删除二叉树
    bTree.DeleteBinaryTree(bTree.GetRoot());
    cout<<endl;
    return 0;
    }


      总结:测试结果,输出数据,截图。

      

    摘要: 对于MFC中所提到的基本容器类,做一个基本的介绍和编程操作。 如有数据结构基础,可以直接看第四部分对容器类的操作。 第一,MFC提供三种基本的容器类:arrays(数组),lists(链表), maps(映射,也称作字典). 第二,各容器类的特征分类类型排序?索引?插入元素查找特定元素重复的元素?ListYesNoFastSlowYesArrayYesBy intSlowSlowYesMapNoBy keyFastFastNo (keys)Yes (values) 第三,模板容器类和非模板容器类 模板容器类:Collection contentsArraysListsMaps任...阅读全文
    posted @ 2011-11-16 16:36 陈昂 阅读(16) | 评论 (0) 编辑
     
    摘要: 展望未来,总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告。 走过的路,回忆起来是那么曲折,把自己的一些心得体会分享给程序员兄弟姐妹们,虽然时代在变化,但是很可能你也会走我已经做过的10年的路程,有些心得体会你可以借鉴一下,觉得说得有道理的你就接纳,觉得说得没道理的,你就抛弃,以下是我发自内心的,给大家的忠告,特别是针对那些小弟弟妹妹们。 01. 自己的户口档案、养老保险、医疗保险、住房公积金一定要保管好。 由于程序员行业每年跳槽一次,我不隐瞒大家,我至少换过5个以上的单位,这期间跳来跳去,甚至是城市都换过3个。还好户口没丢掉,其他都已经是乱了,好几个城市里,都有交...阅读全文
    posted @ 2011-11-07 03:03 陈昂 阅读(792) | 评论 (20) 编辑
     
    摘要: 今天对WINDOWS的HOOK技术进行了应用:主要包括以下:1,HOOK技术原理的了解;2,HOOK技术中的常见钩子应用:键盘钩子,鼠标钩子,消息钩子3,钩子DLL在调用程序EXE中的调试。首先,HOOK技术中的几个常用函数:View Code HHOOK SetWindowsHookEx( int idHook, // type of hook to install HOOKPROC lpfn, // address of hook procedure HINSTANCE hMod, // handle to application instance ...阅读全文
    posted @ 2011-11-04 18:46 陈昂 阅读(1186) | 评论 (3) 编辑
     
    摘要: 这篇文章主要是介绍非客户区的自绘,目前只用了对话框功能。该程序可以实现最大化,最小化,最大化恢复,绘制的效果,如下///////////////////////////////////////////////////////////////////////////以下为源代码: 第一部分,头文件// 对话框非客户区自绘Dlg.h : header file//#if !defined(AFX_DLG_H__29895C86_9D01_4C17_B374_289E36621F88__INCLUDED_)#define AFX_DLG_H__29895C86_9D01_4C17_B374_289E阅读全文
    posted @ 2011-11-03 13:53 陈昂 阅读(99) | 评论 (0) 编辑
     
    摘要: 博客园喜欢你的原因,只因为你是我们程序员的家园!喜欢你的原因,只因为你的博客,可以更方便贴代码,看代码!喜欢你的原因,只因为你的功能比较全,符合我们程序员的习惯!喜欢你的原因,只因为你在这里--博客园~阅读全文
    posted @ 2011-11-03 13:44 陈昂 阅读(5) | 评论 (0) 编辑
  • 相关阅读:
    11g SPA (sql Performance Analyze) 进行升级测试
    SPA游标采集之去除重复
    C++ 实现分数的四则运算
    计算两个数的最大公约数和最小公倍数(欧几里得算法)
    计算a月的第b个星期c
    完数问题
    求整数的最大质因子
    C++ 读取文本文件内容到结构体数组中并排序
    月饼问题PAT B1020(贪心算法)
    路径打印(set以及字符串的相关操作)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2289462.html
Copyright © 2011-2022 走看看