异质树的实现——代码+实验报告

 

异质树的实现——代码+实验报告

 

 

  1. // heterogeneityTree2.cpp : Defines the entry point for the console application.
  2. //
  3. #include "stdafx.h"
  4. #include <iostream.h>
  5. #include <string>
  6. #include <stdlib.h> 
  7. #include <stdio.h>
  8. class Node
  9. {
  10.     protectedchar type ;
  11.     protected: Node* parent ;
  12.     public: Node* children[11] ;
  13.     publicint childNum ;
  14.     publicchar dataStr[20] ;
  15.     public: Node()
  16.     {
  17.         childNum = 0 ;
  18.         parent = NULL ;
  19.         for(int i=0 ; i<11 ; i++)
  20.             children[i]=NULL ;
  21.         //cout<<"执行基类构造函数"<<endl ;
  22.     }
  23.     publicvirtual void setData(char* data) = 0 ;  //纯虚函数
  24.     publicvirtual char* getData() = 0 ;   //纯虚函数
  25.     publicvoid setType(char type)
  26.     {
  27.         this->type = type ;     
  28.     }
  29.     publicchar getType()
  30.     {
  31.         return  type ;  
  32.     }
  33.     publicvoid setParent(Node* parent)
  34.     {
  35.         this->parent = parent ;     
  36.     }
  37.     public: Node* getParent()
  38.     {
  39.         return  this->parent ;  
  40.     }
  41.     public: Node* addChild(Node* childNode)
  42.     {
  43.         childNum++ ;
  44.         if(childNum>=11)
  45.         {
  46.             childNum-- ;
  47.             return NULL ;
  48.         }
  49.         children[childNum] = childNode ;
  50.         childNode->setParent(this) ;
  51.         cout<<"结点"<<childNode->getData()<<"插入在children["<<childNum<<"]位置"<<endl; ;
  52.         return childNode ;
  53.     }
  54.     
  55. };
  56. class IntNode :public Node
  57. {
  58.     privateint data ;
  59.     public: IntNode(char* data)
  60.     {
  61.         this->setType('i') ;
  62.         this->setData(data) ;
  63.         //cout<<"执行派生类含参构造函数"<<endl ;
  64.     }
  65.     publicvoid setData(char* data)
  66.     {
  67.         this->data = atoi(data) ;
  68.     }
  69.     
  70.     publicchar* getData()
  71.     {   
  72.         itoa(this->data , dataStr , 10) ;
  73.         return  dataStr ;
  74.     }
  75. };
  76. class StrNode :public Node
  77. {
  78.     privatechar* data ;
  79.     public: StrNode(char* data)
  80.     {
  81.         this->setType('s') ;
  82.         this->setData(data) ;
  83.     }
  84.              
  85.     publicvoid setData(char* data)
  86.     {
  87.         this->data = data ;
  88.     }
  89.     
  90.     publicchar* getData()
  91.     {   
  92.         return  this->data ;
  93.     }
  94. };
  95. class Helper
  96. {
  97.     publicvoid navTree(Node* node)
  98.     {
  99.         //cout<<"正在遍历树..."<<endl ;
  100.         if(node->getParent()==NULL)
  101.         {
  102.             cout<<(*node).getData()<<" " ;
  103.         }
  104.         int num = (*node).childNum ;
  105.         if( num!=0 )
  106.         {
  107.             for(int i=1 ; i<=num ; i++)
  108.             {
  109.                 Node* child = (*node).children[i] ;
  110.                 cout<<(*child).getData()<<" " ;
  111.                 navTree( child ) ;
  112.             }
  113.         }
  114.     }
  115.     publicvoid findNode(Node* root , char tyChar , char* dataStr , Node *&foundNode)
  116.     {
  117.         int num = (*root).childNum ;
  118.         
  119.         //cout<<"结点"<<root->getData()<<"有"<<num<<"个孩子"<<endl ;
  120.         if( num!=0 )
  121.         {
  122.             for(int i=1 ; i<=num ; i++)
  123.             {
  124.                 Node* child = root->children[i] ;
  125.                 char* childData = child->getData() ;
  126.                 //查找符合要求的结点
  127.                 //cout<<"结点值="<<childData<<"目标值="<<dataStr<<endl ;
  128.                 if( tyChar == child->getType() && strcmpi(childData,dataStr)==0 )
  129.                 {
  130.                     //cout<<"找到该结点:"<<child->getData()<<endl ;
  131.                     foundNode = child ;
  132.                     break ;
  133.                     return ;
  134.                 }
  135.                 else findNode( child , tyChar , dataStr , foundNode) ;
  136.             }// end for
  137.         }
  138.         else return ; 
  139.     }
  140.     privatevoid removeNode(Node* node)
  141.     {
  142.         int num = (*node).childNum ;
  143.         cout<<"结点"<<node->getData()<<"有"<<num<<"个孩子"<<endl ;
  144.         if( num!=0 )
  145.         {
  146.             for(int i=1 ; i<=num ; i++)
  147.             {
  148.                 Node* child = (*node).children[i] ;
  149.                 removeNode( child ) ;
  150.             }
  151.         }
  152.         if( num==0 )
  153.         {
  154.             Node* parent = node->getParent() ;
  155.             cout<<"欲删除结点:"<<node->getData()<<" 其父亲结点有孩子"<<parent->childNum<<"个"<<endl ;
  156.             for(int i=1 ; i<=parent->childNum ; i++)
  157.             {
  158.                 cout<<"parent->children["<<i<<"]="<<parent->children[i]->getData()<<endl ;
  159.                 //cout<<strcmpi(parent->children[i]->getData(),node->getData())<<endl ;
  160.                 //cout<<parent->children[i]->getType()<<node->getType()<<endl ;
  161.                 if( strcmpi(parent->children[i]->getData(),node->getData())==0 
  162.                     &
  163.                     parent->children[i]->getType() == node->getType()
  164.                     )
  165.                 {
  166.                     //delete node ;
  167.                     
  168.                     //cout<<"i="<<i<<"data:"<<parent->children[i]->getData()<<"  指针移位。。。"<<endl ;
  169.                     parent->children[i] = parent->children[i+1] ;
  170.                     //parent->children[i+1] = NULL ;
  171.                     parent->childNum-- ;
  172.                     cout<<"已删除结点"<<node->getData()<<",其父亲结点"<<parent->getData()<<"的孩子数="<<parent->childNum<<endl ;
  173.                     break ;
  174.                 }
  175.             }
  176.             if(parent->childNum==0)
  177.             {
  178.                 removeNode(parent) ;
  179.             }
  180.         
  181.         }//end if(num==0)
  182.     }
  183.     publicvoid deleteNode(Node* root , char tyChar , char* dataStr)
  184.     {
  185.         Node* foundNode = NULL ;
  186.         findNode(root, tyChar, dataStr, foundNode) ;
  187.         
  188.         if(foundNode==NULL) cout<<"查无此结点,无法删除"<<endl ;
  189.         else
  190.         {
  191.             cout<<"找到结点: "<<foundNode->getData()<<",正在删除..."<<endl ;
  192.             removeNode(foundNode) ;
  193.         }
  194.     }
  195.     
  196. };
  197. int main(int argc, char* argv[])
  198. {
  199.     //printf("Hello World!/n");
  200.     
  201.     Node* root = new StrNode("root") ;
  202.     Node* inode1 = new IntNode("1") ;
  203.     Node* inode2 = new IntNode("2") ;
  204.     Node* snode1_1 = new StrNode("1_1") ;
  205.     Node* snode1_2 = new StrNode("1_2") ;
  206.     Node* snode1_1_1 = new StrNode("1_1_1") ;
  207.     Node* snode1_1_2 = new StrNode("1_1_2") ;
  208.     root->addChild(inode1) ;
  209.     root->addChild(inode2) ;
  210.     inode1->addChild(snode1_1) ;
  211.     inode1->addChild(snode1_2) ;
  212.     snode1_1->addChild(snode1_1_1) ;
  213.     snode1_1->addChild(snode1_1_2) ;
  214.     
  215.     Helper helper ;
  216.     /*
  217.     Node* foundNode = NULL ;
  218.     helper.findNode(root , 's' , "1_1", foundNode) ;
  219.     if(foundNode==NULL) cout<<"查无此结点"<<endl ;
  220.     else cout<<"foundNode: "<<foundNode->getData()<<endl ;
  221.     */
  222.     helper.deleteNode(root,'i',"1") ;
  223.     helper.navTree(root) ;
  224.     root->addChild(inode1) ;
  225.     helper.navTree(root) ;
  226.     return 0;
  227. }

北航软件学院《一级实践》实验报告

学号: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类型,仅向用户暴露必要的接口方法间接修改类的成员属性。

你进行了哪些测试

相同类型和不同类型树结点间的查找、插入、删除和遍历操作;

程序进行了哪些有效性检查

程序对用户传入的参数,包括结点数据类型和结点数据进行了有效性验证。

你是如何保证程序的高效率的

在程序中尽可能使用指针运算以代替类对象的传递操作。

注意:实验报告和案例源代码须在本次小组讨论会前提交

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
很抱歉,我无法为您提供完整的代码。但是,我可以为您提供一些实现质链表的基本思路和示例代码质链表是一种链表数据结构,其中每个节点可以存储不同类型的数据。在学生信息管理系统中,我们可以将每个节点表示一个学生,每个学生包含姓名、学号、年龄、性别等信息。我们可以使用结构体来表示每个学生: ```cpp struct Student { string name; string id; int age; char gender; }; ``` 然后,我们可以定义一个节点结构体,其中包含一个指向下一个节点的指针和一个指向学生结构体的指针: ```cpp struct Node { Node* next; void* data; }; ``` 在这里,我们使用 `void*` 指针类型来表示学生结构体的指针,因为我们不确定每个节点存储的是哪种类型的数据。在实际使用时,我们需要将 `void*` 指针强制转换为学生结构体的指针。 接下来,我们可以定义一个链表类来管理节点,实现添加、删除、查找等操作。下面是一个简单的示例代码: ```cpp class StudentList { public: StudentList() { head = nullptr; } void addStudent(Student* student) { Node* node = new Node; node->next = nullptr; node->data = student; if (head == nullptr) { head = node; } else { Node* curr = head; while (curr->next != nullptr) { curr = curr->next; } curr->next = node; } } Student* findStudent(string id) { Node* curr = head; while (curr != nullptr) { Student* student = (Student*)curr->data; if (student->id == id) { return student; } curr = curr->next; } return nullptr; } void removeStudent(string id) { Node* curr = head; Node* prev = nullptr; while (curr != nullptr) { Student* student = (Student*)curr->data; if (student->id == id) { if (prev == nullptr) { head = curr->next; } else { prev->next = curr->next; } delete curr; return; } prev = curr; curr = curr->next; } } void printList() { Node* curr = head; while (curr != nullptr) { Student* student = (Student*)curr->data; cout << "Name: " << student->name << endl; cout << "ID: " << student->id << endl; cout << "Age: " << student->age << endl; cout << "Gender: " << student->gender << endl; cout << endl; curr = curr->next; } } private: Node* head; }; ``` 在这个示例代码中,我们定义了一个 `StudentList` 类来管理学生信息。我们使用 `addStudent` 方法向链表中添加一个学生,使用 `findStudent` 方法查找一个学生,并使用 `removeStudent` 方法删除一个学生。我们还实现了一个 `printList` 方法,用于打印链表中所有学生的信息。 需要注意的是,在使用 `data` 指针时,我们需要将其强制转换为 `Student*` 类型。如果节点存储的是其他类型的数据,我们需要根据实际情况进行转换。此外,在删除节点时,我们需要手动释放内存,以避免内存泄漏。 总体来说,质链表是一种灵活、可扩展的数据结构,适用于存储不同类型的数据。在学生信息管理系统中,我们可以使用质链表来存储学生的信息,实现对学生信息的添加、删除、查找等操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yexianyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值