慕课网学习笔记之数据结构树(C++)

来源:互联网 发布:jenkins自动部署linux 编辑:程序博客网 时间:2024/06/08 00:38

什么是树?——数是节点有限集合
这里写图片描述
孩子:在上图中BCD都是A的孩子,EF是B的孩子,GH是D的孩子
双亲:A是BCD的双亲,B是EF的双亲,D是GH的双亲,注意这里双亲是指一个节点而非两个。
:节点的度等于节点的孩子数。A的度为3,B的度为2,D的度为2,CEFGH度都是0。
叶子:终端节点就是叶子。CEFGH
根:非终端节点。ABD
有序树:举例来说:如果EF不可以换顺序,则为有序树。
无序树:相对于有序树。
祖先:当前节点,一直向上所路过的所有节点直到根都是该节点祖先。
子孙:当前节点,向下的所有节点,都是该节点的子孙。
深度:节点深度为该节点所在层数;树的深度为该树的最大深度。
森林:多颗独立的树在一起就成了森林。
二叉树:所有节点的度都小于等于2。
二叉树的遍历:前序遍历,中序遍历,后序遍历。
这里写图片描述
记忆口诀:根左右、左根右、左右根。
树的应用:压缩软件、人机对战。

二叉树的实现:

1.数组实现
2.链表实现
第一种数组实现的方式较为简单

/*****************************************//* 二叉树(数组表示)     关于数据与树之间的算法转换     int tree[n] 3 5 8 2 6 9 7                                 3(0)            5(1)              8(2)      2(3)      6(4)     9(5)         7(6)    结论:        父亲节点下标*2+1 为该节点左孩子的下标         父亲节点下标*2+2 为该节点右孩子的下标   */ 

当节点不存在时有些不好表达,如果用0来代表无此节点,当存放的数据就是0时便会影响树的操作。
第二种链表实现

/********************************************    节点要素: 索引   数据  左孩子指针   右孩子指针  父节点指针         tree[n] 3 5 8 2 6 9 7                       3(0)            5(1)              8(2)      2(3)      6(4)     9(5)         7(6)      下标来表示遍历顺序:       前序:0 1 3 4 2 5 6      中序:3 1 4 0 5 2 6      后序:3 4 1 5 6 2 0  */

tree.h文件:

#ifndef TREE_H#define TREE_H#include"Node.h"class Tree{public:    Tree();                                                 //创建树       ~Tree();                                               //销毁树     Node *SearchNode(int nodeIndex);                            //根据索引寻找节点     bool AddNode(int nodeIndex,int direction,Node *pNode);  //添加节点     bool DeleteNode(int nodeIndex,Node *pNode);             //删除节点     void PreorderTraverse();                                //前序遍历    void InorderTraverse();                                 //中序遍历     void PostorderTraverse();                               //后序遍历                          private:    Node *m_pRoot;  };#endif

Node.h文件:

#ifndef NODE_H#define NODE_Hclass Node{public :    Node();    Node *SearchNode(int nodeIndex); //寻找索引号所在节点,若存在返回该节点,否则返回NULL     void DeleteNode();               //删除节点     void PreorderTraverse();         //前序遍历     void InorderTraverse();          //中序遍历                 void PostorderTraverse();        //后序遍历     int index;                       //索引号     int data;                        //数据     Node *pLChild;                   //左孩子指针     Node *pRChild;                   //右孩子指针     Node *pParent;                   //双亲指针  };#endif

Node.cpp文件:

#include"Node.h"#include"stdlib.h"#include<iostream>using namespace std; Node::Node()                                        //节点构造函数 {                                                   //初始创建根节点     index=0;                                        // 索引初始化为0     data=3;                                         // 数据初始为3     pLChild=NULL;    pRChild=NULL;    pParent=NULL;}Node *Node::SearchNode(int nodeIndex)               {    if(this->index == nodeIndex)                    //找到返回         return this;    Node *temp;                                     //暂存使用     if(this->pLChild != NULL)                       //左孩子存在     {           if(this->pLChild->index == nodeIndex)             return  this->pLChild;          else                                        //如果没找到         {        temp=this->pLChild->SearchNode(nodeIndex);  //递归调用         if(temp != NULL)            return temp;                            //找到则返回,否则继续向下         }           }       if(this->pRChild != NULL)                       //右孩子存在     {           if(this->pRChild->index == nodeIndex)            return  this->pRChild;                          else                                        //未找到         {        temp=this->pRChild->SearchNode(nodeIndex);  //递归调用             return temp;                            //直接return 出去 不需要继续找         }       }       }void Node::DeleteNode()                             {    if(this->pLChild !=NULL)                        //左孩子存在         this->pLChild->DeleteNode();                //递归调用     if(this->pRChild !=NULL)        this->pRChild->DeleteNode();                //递归调用     if(this->pParent !=NULL)                        //判断自己是双亲的左孩子or右孩子     {        if(this->pParent->pLChild == this)            this->pParent->pLChild=NULL;                    if(this->pParent->pRChild == this)            this->pParent->pRChild=NULL;            //判断出来使双亲该孩子指为NULL     }           delete this;                                    //自己的子孙杀完,双亲对自己指向空,可以自杀了 }void Node::PreorderTraverse()                       //前序遍历,递归调用 {    cout<<this->index<<"          "<<this->data << endl;//打印根     if(this->pLChild !=NULL)                            //左         this->pLChild->PreorderTraverse();              //递归     if(this->pRChild != NULL)                           //右         this->pRChild->PreorderTraverse();              //递归 }            /**中序遍历和后序遍历同理,只需要更改程序执行顺序**/ void Node::InorderTraverse(){    if(this->pLChild !=NULL)         this->pLChild->InorderTraverse();    cout<<this->index<<"          "<<this->data << endl;    if(this->pRChild != NULL)        this->pRChild->InorderTraverse();   }                       void Node::PostorderTraverse(){    if(this->pLChild !=NULL)        this->pLChild->PostorderTraverse();    if(this->pRChild != NULL)        this->pRChild->PostorderTraverse();     cout<<this->index<<"         "<<this->data << endl;}

tree.cpp文件:

#include"stdlib.h"Tree::Tree(){    m_pRoot = new Node();                                   //申请内存 }Tree::~Tree(){//  DeleteNode(0,NULL);                                     //这种方式也能实现销毁树     m_pRoot->DeleteNode();}Node *Tree::SearchNode(int nodeIndex){    return m_pRoot->SearchNode(nodeIndex);                  //根节点调用查找 }bool Tree::AddNode(int nodeIndex,int direction,Node *pNode) // 索引号,左(0)右(1)孩子 ,要插入的节点 {    Node *temp =SearchNode(nodeIndex);                      //先查找     if(temp==NULL)        return false;                                       //不存在则不能插入     Node *node = new Node();                                //申请新节点     if(node==NULL)                                          //申请是否成功         return false;    node->index = pNode->index;                             //传入索引号     node->data = pNode->data;                               //传入数据     node->pParent = temp;                   //这很关键,涉及到删除的成功与否 ,指出插入的节点双亲是谁     if(0==direction)        temp->pLChild = node;    if(1==direction)        temp->pRChild = node;    return true;        }bool Tree::DeleteNode(int nodeIndex,Node *pNode){    Node *temp =SearchNode(nodeIndex);                  //先找到才能删     if(temp==NULL)        return false;    if(pNode != NULL)                       pNode->data=temp->data;                         //删除数据可以传出     temp->DeleteNode();                                 //调用Node.cpp中的删除方法     return true;        }/**以下是三种遍历,实现在Node.cpp里定义**/ void Tree::PreorderTraverse(){    m_pRoot->PreorderTraverse();}void Tree::InorderTraverse(){    m_pRoot->InorderTraverse() ;}void Tree::PostorderTraverse(){    m_pRoot->PostorderTraverse();}

domo.cpp文件(用于验证):

#include<iostream>#include"Tree.h"using namespace std;int main()  {     Node node1;    node1.index=1;    node1.data = 5;    Node node2;    node2.index=2;    node2.data = 8;    Node node3;    node3.index=3;    node3.data = 2;    Node node4;    node4.index=4;    node4.data = 6;    Node node5;    node5.index=5;    node5.data = 9;    Node node6;    node6.index=6;    node6.data = 7;    Tree *pTree = new Tree();       pTree->AddNode(0,0,&node1);    pTree->AddNode(0,1,&node2);    pTree->AddNode(1,0,&node3);    pTree->AddNode(1,1,&node4);    pTree->AddNode(2,0,&node5);    pTree->AddNode(2,1,&node6);    cout<<"PreorderTraverse: "  <<endl;    cout<<"index" <<"   "<<"data"<<endl;    pTree->PreorderTraverse();    cout<<"InorderTraverse: "   <<endl;    cout<<"index" <<"   "<<"data"<<endl;    pTree->InorderTraverse();    cout<<"PostorderTraverse: " <<endl;    cout<<"index" <<"   "<<"data"<<endl;    pTree->PostorderTraverse();    pTree->DeleteNode(6,NULL);    cout<<"PreorderTraverse: "  <<endl;    pTree->PreorderTraverse();    delete pTree;    pTree= NULL;    return 0;}

运行结果:
这里写图片描述

0 0
原创粉丝点击