异质树的实现——代码+实验报告
Posted yexianyi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异质树的实现——代码+实验报告相关的知识,希望对你有一定的参考价值。
异质树的实现——代码+实验报告
- // heterogeneityTree2.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <iostream.h>
- #include <string>
- #include <stdlib.h>
- #include <stdio.h>
- class Node
- {
- protected: char type ;
- protected: Node* parent ;
- public: Node* children[11] ;
- public: int childNum ;
- public: char dataStr[20] ;
- public: Node()
- {
- childNum = 0 ;
- parent = NULL ;
- for(int i=0 ; i<11 ; i++)
- children[i]=NULL ;
- //cout<<"执行基类构造函数"<<endl ;
- }
- public: virtual void setData(char* data) = 0 ; //纯虚函数
- public: virtual char* getData() = 0 ; //纯虚函数
- public: void setType(char type)
- {
- this->type = type ;
- }
- public: char getType()
- {
- return type ;
- }
- public: void setParent(Node* parent)
- {
- this->parent = parent ;
- }
- public: Node* getParent()
- {
- return this->parent ;
- }
- public: Node* addChild(Node* childNode)
- {
- childNum++ ;
- if(childNum>=11)
- {
- childNum-- ;
- return NULL ;
- }
- children[childNum] = childNode ;
- childNode->setParent(this) ;
- cout<<"结点"<<childNode->getData()<<"插入在children["<<childNum<<"]位置"<<endl; ;
- return childNode ;
- }
- };
- class IntNode :public Node
- {
- private: int data ;
- public: IntNode(char* data)
- {
- this->setType('i') ;
- this->setData(data) ;
- //cout<<"执行派生类含参构造函数"<<endl ;
- }
- public: void setData(char* data)
- {
- this->data = atoi(data) ;
- }
- public: char* getData()
- {
- itoa(this->data , dataStr , 10) ;
- return dataStr ;
- }
- };
- class StrNode :public Node
- {
- private: char* data ;
- public: StrNode(char* data)
- {
- this->setType('s') ;
- this->setData(data) ;
- }
- public: void setData(char* data)
- {
- this->data = data ;
- }
- public: char* getData()
- {
- return this->data ;
- }
- };
- class Helper
- {
- public: void navTree(Node* node)
- {
- //cout<<"正在遍历树..."<<endl ;
- if(node->getParent()==NULL)
- {
- cout<<(*node).getData()<<" " ;
- }
- int num = (*node).childNum ;
- if( num!=0 )
- {
- for(int i=1 ; i<=num ; i++)
- {
- Node* child = (*node).children[i] ;
- cout<<(*child).getData()<<" " ;
- navTree( child ) ;
- }
- }
- }
- public: void findNode(Node* root , char tyChar , char* dataStr , Node *&foundNode)
- {
- int num = (*root).childNum ;
- //cout<<"结点"<<root->getData()<<"有"<<num<<"个孩子"<<endl ;
- if( num!=0 )
- {
- for(int i=1 ; i<=num ; i++)
- {
- Node* child = root->children[i] ;
- char* childData = child->getData() ;
- //查找符合要求的结点
- //cout<<"结点值="<<childData<<"目标值="<<dataStr<<endl ;
- if( tyChar == child->getType() && strcmpi(childData,dataStr)==0 )
- {
- //cout<<"找到该结点:"<<child->getData()<<endl ;
- foundNode = child ;
- break ;
- return ;
- }
- else findNode( child , tyChar , dataStr , foundNode) ;
- }// end for
- }
- else return ;
- }
- private: void removeNode(Node* node)
- {
- int num = (*node).childNum ;
- cout<<"结点"<<node->getData()<<"有"<<num<<"个孩子"<<endl ;
- if( num!=0 )
- {
- for(int i=1 ; i<=num ; i++)
- {
- Node* child = (*node).children[i] ;
- removeNode( child ) ;
- }
- }
- if( num==0 )
- {
- Node* parent = node->getParent() ;
- cout<<"欲删除结点:"<<node->getData()<<" 其父亲结点有孩子"<<parent->childNum<<"个"<<endl ;
- for(int i=1 ; i<=parent->childNum ; i++)
- {
- cout<<"parent->children["<<i<<"]="<<parent->children[i]->getData()<<endl ;
- //cout<<strcmpi(parent->children[i]->getData(),node->getData())<<endl ;
- //cout<<parent->children[i]->getType()<<node->getType()<<endl ;
- if( strcmpi(parent->children[i]->getData(),node->getData())==0
- &
- parent->children[i]->getType() == node->getType()
- )
- {
- //delete node ;
- //cout<<"i="<<i<<"data:"<<parent->children[i]->getData()<<" 指针移位。。。"<<endl ;
- parent->children[i] = parent->children[i+1] ;
- //parent->children[i+1] = NULL ;
- parent->childNum-- ;
- cout<<"已删除结点"<<node->getData()<<",其父亲结点"<<parent->getData()<<"的孩子数="<<parent->childNum<<endl ;
- break ;
- }
- }
- if(parent->childNum==0)
- {
- removeNode(parent) ;
- }
- }//end if(num==0)
- }
- public: void deleteNode(Node* root , char tyChar , char* dataStr)
- {
- Node* foundNode = NULL ;
- findNode(root, tyChar, dataStr, foundNode) ;
- if(foundNode==NULL) cout<<"查无此结点,无法删除"<<endl ;
- else
- {
- cout<<"找到结点: "<<foundNode->getData()<<",正在删除..."<<endl ;
- removeNode(foundNode) ;
- }
- }
- };
- int main(int argc, char* argv[])
- {
- //printf("Hello World!/n");
- Node* root = new StrNode("root") ;
- Node* inode1 = new IntNode("1") ;
- Node* inode2 = new IntNode("2") ;
- Node* snode1_1 = new StrNode("1_1") ;
- Node* snode1_2 = new StrNode("1_2") ;
- Node* snode1_1_1 = new StrNode("1_1_1") ;
- Node* snode1_1_2 = new StrNode("1_1_2") ;
- root->addChild(inode1) ;
- root->addChild(inode2) ;
- inode1->addChild(snode1_1) ;
- inode1->addChild(snode1_2) ;
- snode1_1->addChild(snode1_1_1) ;
- snode1_1->addChild(snode1_1_2) ;
- Helper helper ;
- /*
- Node* foundNode = NULL ;
- helper.findNode(root , 's' , "1_1", foundNode) ;
- if(foundNode==NULL) cout<<"查无此结点"<<endl ;
- else cout<<"foundNode: "<<foundNode->getData()<<endl ;
- */
- helper.deleteNode(root,'i',"1") ;
- helper.navTree(root) ;
- root->addChild(inode1) ;
- helper.navTree(root) ;
- return 0;
- }
北航软件学院《一级实践》实验报告
学号:GS0821594 姓名:叶现一 第 9 周
内容训练
异质树的实现
本周开发源代码
代码的功能简述
实现异质树的查找、插入、删除和遍历
开发的收获
关于纯虚函数的使用;类的继承的使用;派生类对象的初始化;指针引用;递归函数的使用
开发中碰到的主要困难
1) 在选择实现方案上:曾经设想用共用体的方式解决树的不同结点存储不同数据类型的数据问题,但该方案其一比较浪费内存,其二要针对不同的结点类型定义不同的插入子结点策略、删除子结点策略等。后期编写比较困难,而且难以维护。
2) 在编写对树结点的查找函数时,找不到有效的办法能使找到的结点地址被成功的返回。最终采用了指针引用的方式将地址返回。
3) 在保存一个结点的子结点策略上:因为一个普通树结点的子结点没有固定的数量,所以理论上应该采用一个链表用于保存一个结点上的子结点,但此方案的前提是已经有一个工作良好的链表类用于使用。由于为此目的单独开发一个链表类相当耗时,所以最终采用了次方案——用一个固定大小的数组用于保存该结点的所有子结点的地址。这种方案固然不是一个很好的方案,因为限定了数组的大小就等于限定了一个结点所能拥有的子结点的数量。还有一个较好的方案则是使用STL中已经定义好的链表类,不仅功能齐备而且性能可靠。但由于未能掌握其基本使用方法该方案最终未能得以实施。
4) 关于删除结点问题:由于采用了定长数组保存每个结点的子结点地址,且在删除一个结点的同时应该将其后代全部删除,但在每删除一个结点的时候都应该将其地址从该结点的父结点中的子结点列表中删除。于是就引出了以下问题——如果假定一个结点的子结点列表(数组)中3个成员变量(子结点地址),分别存储在1位、2位和3位上,现要删除2位上的结点。当将2位上的地址清空后需要将其后的地址依次向前移动一个单元,否则在删除完该结点后立刻进行树的遍历操作时会产生运行时错误。因为根据递归调用,程序并不清楚2位上的地址段中的结点已经被删除。
开发中未能解决的问题
1) 关于上述开发困难中的(2):我认为可以找到更直接更人性化的方法将找到的树结点的地址返回来,而不是用指针引用。因为我们通常习惯用Node* foundNode = findNode(root,typeChar,dataStr);的方式获取到结点的地址,而不是通过Node* foundNode = NULL ;
findNode(root, tyChar,dataStr,foundNode);
的方式获取结点地址。我正在考虑使用指向指针的指针以解决该问题。
2) 关于上述开发困难中的(3)和(4):希望能够采用一个链表来保存一个结点的所有子结点的地址而不是定长数组。这需要借助于STL的链表类,因此该程序有待于在掌握STL的具体使用方法后做进一步的改进。
3) 在删除树结点的过程中不能做到真实的释放树结点的地址空间,即执行语句delete node;因此在本程序中对结点的删除只是假删除——只把结点的子结点地址从该结点的子结点列表中删除掉,而其子结点的空间并没有释放掉,今后还可以重用。这是极不安全的一种实现方案,迫切需要更正!
针对本周训练内容自己设计的案例
案例的主要功能
实现异质树的查找、插入、删除和遍历
用到的基本知识
纯虚函数的使用;类的继承的使用;派生类对象的初始化;指针引用;递归函数的使用
程序注意了哪些规范
1) 使用了抽象类与类继承关系,最大限度的提高了代码的重用性。
2) 将结点类的关键成员变量或方法设定为private或者protected类型,仅向用户暴露必要的接口方法间接修改类的成员属性。
你进行了哪些测试
相同类型和不同类型树结点间的查找、插入、删除和遍历操作;
程序进行了哪些有效性检查
程序对用户传入的参数,包括结点数据类型和结点数据进行了有效性验证。
你是如何保证程序的高效率的
在程序中尽可能使用指针运算以代替类对象的传递操作。
注意:实验报告和案例源代码须在本次小组讨论会前提交
以上是关于异质树的实现——代码+实验报告的主要内容,如果未能解决你的问题,请参考以下文章