• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > C++如何实现广义表详解

C++如何实现广义表详解

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c++关键字详解,c++指针详解,c++编程实例详解,c++编程实例详解pdf,c++socket编程详解等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

以下给出几种简单的广义表模型:

 

由上图我们可以看到,广义表的节点类型无非head、value、sub三种,这里设置枚举类型,利用枚举变量来记录每个节点的类型:

enum Type
{
  HEAD,  //头节点
  VALUE, //值节点
  SUB,  //子表节点
};
</div>

每个节点都有自己的类型以及next指针,除此之外,如果该节点是VALUE类型还要分配空间存储该节点的有效值;但是若该节点是SUB类型,就需定义一个指针指向子表的头。

这里我们可以用联合来解决这个问题。

(联合(或共同体)是一种不同数据类型成员之间共享存储空间的方法,并且联合体对象在同一时间只能存储一个成员值)

构造节点:

struct GeneralizedNode
{
  Type _type;    // 1.类型
  GeneralizedNode* _next; //2.指向同层的下一个节点
  union
  {
    char _value;  // 3.有效值
    GeneralizedNode* _subLink;   // 3.指向子表的指针
  };
   
  GeneralizedNode(Type type = HEAD, char value = '0')
  :_value(value)
  ,_type(type)
  , _next(NULL)
  {
    if (_type == SUB)
    {
      _subLink = NULL;
    }
  }
};
</div>

广义表的定义及基本操作: 

class Generalized
{
public:
  //无参的构造函数,建立空的广义表
  Generalized();
  //建造广义表,有参数的构造函数
  Generalized(const char* str);
  //打印广义表
  void Print();
  //获取值节点的个数
  size_t Amount();
  //获取广义表的深度
  size_t Depth();
  //拷贝构造
  Generalized(const Generalized& g);
  ////赋值运算符的重载
  Generalized& operator=(const Generalized& g);
  ////析构函数
  ~Generalized();
 
protected:
  void _Print(GeneralizedNode* head);
  GeneralizedNode* _CreatList(const char*& str);
  size_t _Amount(GeneralizedNode* head);
  GeneralizedNode* _Copy(GeneralizedNode* head);
  void _Destory(GeneralizedNode* head);
protected:
  GeneralizedNode* _head;  //记录广义表头指针
};
</div>

初始化建立广义表进行循环递归。遍历字符串时遇到字符就建立值节点,遇到'('就进行递归并建立子表;遇到')'就结束当前子表的建立,并返回当前子表的头指针。 

GeneralizedNode* _CreatList(const char*& str)
{
  assert(*str == '(');
  GeneralizedNode* head = new GeneralizedNode(HEAD,'0');
  GeneralizedNode* cur = head;
  str++;
  while (str != '\0')
  {
    if ((*str >= '0'&&*str <= '9') || (*str >= 'a'&&*str <= 'z') || (*str >= 'A'&&*str <= 'Z'))
    {
      cur->_next = new GeneralizedNode(VALUE, *str);
      cur = cur->_next;
    }
    else if (*str == '(')
    {
      cur->_next = new GeneralizedNode(SUB);
      cur = cur->_next;
      cur->_subLink = _CreatList(str);
    }
    else if (*str == ')')
    {
      return head;
    }
    str++;
  }
  return head;
}
</div>

打印广义表:当节点的类型为SUB时进行递归,最后不要忘了每打印完一层要打印一个后括号。

void _Print(GeneralizedNode* head)
{
  if (head == NULL)
  {
    cout << "Generalized table is NULL" << endl;
    return;
  }
  GeneralizedNode* cur = head;
  while (cur)
  {
    if (cur->_type == HEAD)
    {
      cout << '(';
    }
    else if (cur->_type == VALUE)
    {
      cout << cur->_value;
      if (cur->_next)
      {
        cout << ',';
      }
    }
    else if (cur->_type == SUB)
    {
      _Print(cur->_subLink);
      if (cur->_next)
      {
        cout << ',';
      }       
    }
    cur = cur->_next;
  }
  cout << ')';
}
</div>

获取值节点的个数:设置count变量,遇到值节点就加1,遇到SUB节点进行递归并将返回值加给count

size_t _Amount(GeneralizedNode* head)
{
  GeneralizedNode* begin = head;
  size_t count = 0;
  while (begin)
  {
    if (begin->_type == VALUE)
    {
      count++;
    }
    if (begin->_type == SUB)
    {
      count += _Amount(begin->_subLink);
    }
    begin = begin->_next;
  }
  return count;
}
</div>

广义表的深度:设置变量dp和max分别用来记录当前子表即当前SUB节点指向的子表深度,以及本层所有的SUB节点中深度最大的子表的深度。

size_t _Depth(GeneralizedNode* head)
{
  if (_head == NULL)
  {
    return 0;
  }
  size_t dp=0;
  GeneralizedNode* cur = head;
  size_t max = 0;
  while (cur)
  {
    if (cur->_type == SUB)
    {
      dp=_Depth(cur->_subLink);
      if (max < dp)
      {
        max = dp;
      }
    }
    cur = cur->_next;
  }
  return max+1;
}
</div>

销毁广义表:依次遍历节点,遇到子表递归,将子表的节点delete完成后,再回到当前层继续遍历。

void _Destory(GeneralizedNode* head)
{
  if (head == NULL)
  {
    return;
  }
  while (head)
  {
    GeneralizedNode* begin = head->_next;
    if (head->_type == SUB)
    {
      _Destory(head->_subLink);
    }
    delete head;
    head = begin;
  }
}
</div>

实例演示

定义:

广义表是n(n≥0)个元素a1,a2,…,ai,…,an的有限序列。

  其中:

  ①ai--或者是原子或者是一个广义表。

  ②广义表通常记作:

  Ls=( a1,a2,…,ai,…,an)。

  ③Ls是广义表的名字,n为它的长度。

  ④若ai是广义表,则称它为Ls的子表。

  注意:

  ①广义表通常用圆括号括起来,用逗号分隔其中的元素。

  ②为了区分原子和广义表,书写时用大写字母表示广义表,用小写字母表示原子。

  ③若广义表Ls非空(n≥1),则al是LS的表头,其余元素组成的表(a1,a2,…,an)称为Ls的表尾。

  ④广义表是递归定义的

画图举例:

代码实现:

[cpp] view plain copy
#include <iostream> 
 
using namespace std; 
 
//表示广义表的结点类型 
enum NodeType 
{ 
  HEAD_TYPE,//头结点类型 
  VALUE_TYPE,//值结点类型 
  SUB_TYPE//子表类型 
}; 
 
//表示广义表结点的结构体 
struct GeneraListNode 
{ 
  NodeType _type;//结点类型 
  GeneraListNode *_next;//存放结点的下一个元素的地址 
 
  //一个结点要么是值结点要么是子表,故用联合体来存放节省一定的空间 
  //若是值结点则存放的是值,是子表结点的话存放的是子表结点头结点的地址 
  union{ 
    char _value; 
    GeneraListNode *_subLink; 
  }; 
 
  GeneraListNode(NodeType type = HEAD_TYPE, char value = '\0') 
    :_type(type) 
    ,_next(NULL) 
  { 
    if (type == VALUE_TYPE) 
    { 
      _value = value; 
    }else if(type == SUB_TYPE) 
    { 
      _subLink = NULL; 
    } 
 
  } 
 
}; 
 
class GeneraList 
{ 
private: 
  GeneraListNode *_link;//用来存放广义表头结点地址 
public: 
  GeneraList(const char *str) 
    :_link(NULL) 
  { 
    _CreateGeneraList(_link, str);//根据指定序列创建广义表 
  } 
 
  ~GeneraList() 
  {} 
public: 
  void Print();//对外提供的打印广义表的接口 
  int Size();//广义表中值结点的数目的对外获取接口 
  int Depth();//广义表的最深层次的对外获取接口 
private: 
  void _CreateGene



 
分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C++的虚析构详解及实例代码
  • C++ 中函数重载、覆盖与隐藏详解
  • C++中函数重载实例详解
  • C++模版函数详解
  • 详解C++11中的右值引用与移动语义
  • C++详解默认参数的构造函数及简单实例代码
  • C++如何动态的生成对象详解
  • C++ 反射机制详解及实例代码
  • C++ 处理中文符号实例详解
  • c++中虚函数的实现详解

相关文章

  • 2017-05-28浅谈C++重载、重写、重定义
  • 2017-05-28C语言中的setlinebuf()、utmpname()、rewind函数使用
  • 2017-05-28使用dc画笔画矩形、直线与椭圆示例
  • 2017-08-17C和C++的内存操作小贴士(一):const char*的内存释放问题
  • 2017-05-28C++计数排序详解
  • 2017-05-28Linux中使用VS Code编译调试C++项目详解
  • 2017-05-28C++初始化列表学习
  • 2017-05-28opencv 做人脸识别 opencv 人脸匹配分析
  • 2017-05-28C++检查某个文件或目录是否存在的函数
  • 2017-05-28基于指针的数据类型与指针运算小结

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • socket多人聊天程序C语言版(一)
    • C语言中#define与typedef的互换细节详解
    • window调用api列出当前所有进程示例
    • C++ 将文件数据一次性加载进内存实例代码
    • 错误:sem_union的存储大小未知问题的解决方法
    • 基础C语言编程时易犯错误有哪些
    • C语言中等待socket连接和对socket定位的方法
    • C++设计模式之工厂方法模式
    • 全面解析C++中的new,operator new与placement new
    • C语言中自动隐式转换与类型强制转换实例分析

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有