数据结构之用C++实现广义表

  广义表,相对于链表较复杂,相对于树又较简单....用来过渡顺序表和树是非常好的选择.

  废话不多说,一言不合就贴代码.

/*
*文件说明:广义表相关声明及定义
*作者:高小调
*日期:2016-12-12
*集成开发环境:Microsoft Visual Studio 2010
*/
#ifndef __GENERALLIST_H__
#define __GENERALLIST_H__
#include<assert.h>
enum Type{
	HEAD,
	SUB,
	VALUE
};
struct GeneralListNode{
	Type type;
	union{
		char value;
		GeneralListNode *sublink;
	};
	GeneralListNode *next;
	GeneralListNode(Type t,const char v = 0)
		:type(t)
		,next(0){
			if(t == HEAD || t ==VALUE){
				value = v;
			}else if(t == SUB){
				sublink = 0;
			}else {
				assert(false);
			}
	}
};

class GeneralList{
typedef GeneralListNode Node;
public:
	//构造函数
	GeneralList(const char *s){
		_head = _CreateList(s);
	}
	//拷贝构造
	GeneralList(const GeneralList &g){
		_head = _Copy(g._head);
	}
	//赋值运算符重载
	GeneralList &operator=(const GeneralList &g){
		if(_head!=g._head){		//不是自己给自己赋值
			GeneralList temp(g);
			swap(_head,temp._head);
		}
	}
	//析构函数
	~GeneralList(){
		if(_head!=NULL){
			_Destory(_head);
			_head = NULL;
		}
	}
public:
	//打印广义表
	void Print(){
		_Print(_head);
		cout<<endl;
	}
	//广义表数据个数
	size_t Size(){
		return _Size(_head);
	}
	//广义表深度
	size_t Depth(){
		return _Depth(_head);
	}
protected:
	//拷贝广义表
	Node * _Copy(Node* head){
		Node *NewHead = new Node(HEAD);
		Node *Tail = NewHead;
		Node *cur = head;
		while(cur){
			if(cur->type == VALUE){							//数据节点
				Tail->next = new Node(VALUE,cur->value);	//创建新节点,添加至尾节点
				Tail = Tail->next;							//尾节点后移
				cur = cur->next;							//被拷贝节点后移
			}else if(cur->type == SUB){						//子表节点
				Node *NewSub = new Node(SUB);				//创建新子表节点
				Tail->next = NewSub;						//添加至尾节点
				Tail = Tail->next;							//尾节点后移
				NewSub->sublink = _Copy(cur->sublink);		//递归拷贝子节点
				cur = cur->next;							//被拷贝节点后移
			}else if(cur->type == HEAD){					//头节点
				cur = cur->next;							//被拷贝节点后移
			}else{
				assert(false);			//出错!
			}
		}
		return NewHead;
	}
	//交换
	void _Swap(Node* &l,Node *&r){
		Node *tmp = l;
		l = r;
		r = tmp;
	}
	//销毁
	void _Destory(Node *head){
		Node *cur = head;
		while(cur){
			if((cur->type == VALUE)
				||(cur->type == HEAD)){		//当前节点为头节点或数据节点
				Node *del = cur;			//保存当前节点
				cur = cur->next;			//当前节点后移
				delete del;					//删除节点
			}else if(cur->type == SUB){		//当前节点为子表
				Node * del = cur;			//保存当前节点
				cur = cur->next;			//当前节点后移
				_Destory(del->sublink);		//递归销毁子表里的数据
				delete del;					//销毁子表
			}else{
				assert(false);				//程序运行出错!
			}

		}
	}
	//判断是否为数据
	bool _IsValue(const char s){
		if((s>=‘0‘&&s<=‘9‘)
			||(s>=‘a‘&&s<=‘z‘)
			||(s>=‘A‘&&s<=‘Z‘)){
			return true;
		}
		return false;
	}
	//递归创建广义表
	Node *_CreateList(const char * &s){
		assert(*s==‘(‘);						//断言字符串s第一个字符是(
		++s;									//跳过(进入数据部分
		Node *head = new Node(HEAD);			//创建头节点
		Node *Tail = head;						//作为尾节点,来插入新数据
		while(*s){
			if(_IsValue(*s)){						//数据项
				Tail->next = new Node(VALUE,*s);	//创建数据节点
				Tail = Tail->next;					//尾节点后移
				++s;
			}else if(*s == ‘(‘){				//子表项
				Node *NewNode = new Node(SUB);	//创建子表节点
				Tail->next = NewNode;			//插入尾部
				Tail = Tail->next;				//尾部后移
				NewNode->sublink = _CreateList(s);	//递归创建子表数据节点
			}else if(*s ==‘)‘){						//数据结束
				++s;
				return head;						//返回头节点
			}else{
				++s;								//遇到逗号跳过
			}
		}
		return head;
	}
	//递归打印广义表
	void _Print(Node *head){
		Node * cur = head;
		while(cur){
			if(cur->type == HEAD){			//头节点
				cout<<"(";
			}else if(cur->type == VALUE){	//值节点
				cout<<cur->value;
				if(cur->next!=NULL){		//不是最后一个元素
					cout<<",";				//以逗号分隔
				}
			}else if(cur->type == SUB){		//子表项
				_Print(cur->sublink);		//递归打印子表
				if(cur->next!=NULL){		//不是最后一项数据
					cout<<",";				//以逗号分隔
				}
			}else{
				assert(false);
			}
			cur = cur->next;
		}
		cout<<")";
	}
	//递归获取广义表数据个数
	size_t _Size(Node *head){
		Node *cur = head;
		size_t ret = 0;
		while(cur){
			if(cur->type ==VALUE){			//当前为值节点
				++ret;						//数据个数+1
			}else if(cur->type ==SUB){
				ret += _Size(cur->sublink);	//递归求取子表数据个数
			}else{
				//头节点
			}
			cur = cur->next;
		}
		return ret;
	}
	//递归求广义表深度
	size_t _Depth(Node *head){
		Node *cur = head;
		size_t MaxDepth = 1;						//当前深度为1
		while(cur){
			if(cur->type == SUB){					//遇到子表
				size_t Depth = _Depth(cur->sublink);//递归求子表深度
				if(MaxDepth<Depth+1){				//如果子表深入大于当前值
					MaxDepth = Depth+1;				//更新最大深入
				}
			}
			cur = cur->next;
		}
		return MaxDepth;							//返回最大深度
	}
private:
	Node * _head;
};
#endif

  

/*
*文件说明:测试文件
*作者:高小调
*日期:2016-12-12
*集成开发环境:Microsoft Visual Studio 2010
*/
#include<iostream>
using namespace std;
#include"GeneralList.h"
void GeneralListTest(){
	const char * const str1 = "(a)";
	GeneralList g1(str1);
	g1.Print();
	cout<<"Size = "<<g1.Size()<<endl;
	cout<<"Depth = "<<g1.Depth()<<endl;

	const char * const str2 = "(a,b)";
	GeneralList g2(str2);
	g2.Print();
	cout<<"Size = "<<g2.Size()<<endl;
	cout<<"Depth = "<<g2.Depth()<<endl;

	const char * const str3 = "(a,b,(c,d))";
	GeneralList g3(str3);
	g3.Print();
	cout<<"Size = "<<g3.Size()<<endl;
	cout<<"Depth = "<<g3.Depth()<<endl;

	const char * const str4 = "((e,(f),h))";
	GeneralList g4(str4);
	g4.Print();
	cout<<"Size = "<<g4.Size()<<endl;
	cout<<"Depth = "<<g4.Depth()<<endl;

	const char * const str5 = "(((1,2)),((3,4)))";
	GeneralList g5(str5);
	g5.Print();
	cout<<"Size = "<<g5.Size()<<endl;
	cout<<"Depth = "<<g5.Depth()<<endl;

	cout<<"////////拷贝构造//////"<<endl<<endl;
	//(a)
	GeneralList g6(g1);
	g6.Print();
	cout<<"Size = "<<g6.Size()<<endl;
	cout<<"Depth = "<<g6.Depth()<<endl;
	//(a,b)
	GeneralList g7(g2);
	g7.Print();
	cout<<"Size = "<<g7.Size()<<endl;
	cout<<"Depth = "<<g7.Depth()<<endl;

	//(a,b,(c,d))
	GeneralList g8(g3);
	g8.Print();
	cout<<"Size = "<<g8.Size()<<endl;
	cout<<"Depth = "<<g8.Depth()<<endl;

	GeneralList g9(g4);
	g9.Print();
	cout<<"Size = "<<g9.Size()<<endl;
	cout<<"Depth = "<<g9.Depth()<<endl;

	GeneralList g10(g5);
	g10.Print();
	cout<<"Size = "<<g10.Size()<<endl;
	cout<<"Depth = "<<g10.Depth()<<endl;
}
int main(){
	GeneralListTest();
	return 0;
}

  总结:

  第一次接触这个,还确实有点难办,写得我脑袋都透支了,还专门打了几把LOL休息了一下....

  这个东西并不是有多难,仅仅是因为递归程序,极其难于调试.当程序出问题时,调试比较让人抓狂!

  还有一点就是,个人太钻牛角尖.有时候及时接受别人的知识,然后纳入自己的知识体系,比自己死磕要快得多....

时间: 2024-11-25 14:31:48

数据结构之用C++实现广义表的相关文章

数据结构实践项目——数组和广义表

本文针对 [数据结构基础系列网络课程(5):数组和广义表] 1. 数组的基本概念与存储结构 2. 特殊矩阵的压缩存储 3. 稀疏矩阵的三元组表示 4. 稀疏矩阵的十字链表表示 5. 广义表 6. 广义表的存储结构及基本运算的实现 [项目1 - 猴子选大王(数组版)] 一群猴子,编号是1,2,3 -m,这群猴子(m个)按照1-m的顺序围坐一圈.从第1只开始数,每数到第n个,该猴子就要离开此圈,这样依次下来,最后一只出圈的猴子为大王.输入m和n,输出猴子离开圈子的顺序,从中也可以看出最后为大王是几号

数据结构 - 数组、矩阵、广义表存储

数组的定义 数组的定义 数组是下标index 和值value 组成的序对的集合. 在数组中,每个有定义的下标都与一个值对应,这个值称做数组元素. 每个序对形如: (index,value) 数组的顺序表示和实现 由于计算机的内存结构是一维的,因此用一维内存来表示多维数组,就必须按某种次序将数组元素排成一列序列,然后将这个线性序列存放在存储器中. 一般都是采用顺序存储的方法来表示数组 一维数组的顺序表示 设第一个数组元素a[0]的存储地址是loc(a[0]),若已知每个数组元素占k个存储单元,则下

数据结构22:数组和广义表

本章主要介绍了数组和广义表的相关知识.数组章节,重点理解矩阵压缩存储的方式,在此基础上,学习矩阵的转置.乘法.和加法运算的实现:学习广义表时重点理解用递归的思想求广义表的深度和复制广义表. 本章内容: 1. 数据结构之多维数组 2. 矩阵压缩存储(十字链表.三元组顺序表.行逻辑 3. 矩阵转置算法及代码实现(三元组顺序表) 4. 矩阵乘法(行逻辑链接的顺序表)及代码实现 5. 矩阵加法(基于十字链表)及C语言代码实现 6. 广义表及M元多项式的C语言代码实现 7. 广义表的长度和深度 8. 广义

数据结构之---C语言实现广义表头尾链表存储表示

//广义表的头尾链表存储表示 //杨鑫 #include <stdio.h> #include <malloc.h> #include <stdlib.h> #include <string.h> #define MAXSTRLEN 40 ) typedef char SString[MAXSTRLEN+1]; typedef char AtomType; // 定义原子类型为字符型 typedef enum{ ATOM, LIST // ATOM==0:原

数据结构4(数组和广义表)

第4章  数组和广义表 [例4-1]二维数组A的每一个元素是由6个字符组成的串,其行下标i=0,1,…,8,列下标j=1,2,…,10.若A以行为主序存储元素,A[8][5]的物理地址与当A按列为主序存储时的元素(  )的物理地址相同.设每个字符占一个字节. A.A[8][5]    B.A[3][10]    C.A[5][8]    D.A[0][9] //作图 解:  二维数A是一个9行10列的矩阵,即A[9][10].按行存储时,A[8][5]是第85个元素存储的元素.而按列存储时,第8

数据结构(C语言第2版)-----数组,广义表,树,图

任何一个算法的设计取决于选定的数据结构,而算法的实现依赖于采用的存储结构. 之前线性表的数据元素都是非结构的原子类型,元素的值是不可再分的.下面学习的这两个线性表是很特殊的,其中数据元素本身也可能是一种数据结构. 认识数组和广义表 数组可以看成是一种特殊的线性表,也就是线性表中的数据元素本身也是一个线性表,数组中的个元素具有统一的类型.其实说白了就是在脑海中想数组中的数据如何在内存中以什么形式的线性表来存储.在C语言中,一个二维数组可以定义为其分量类型为一维数组类型的一维数组类型. 数组一旦被建

数据结构与算法系列研究四——数组和广义表

稀疏矩阵的十字链表实现和转置 一.数组和广义表的定义 数组的定义1:一个 N 维数组是受 N 组线性关系约束的线性表.           二维数组的逻辑结构可形式地描述为:           2_ARRAY(D,R)              其中 D={aij} | i=0,1,...,b1-1; j=0,1,...,b2-1;aij∈D0}              R={Row,Col}              Row={<aij,ai,j+1>|0<=i<=b1-1;

33. 蛤蟆的数据结构笔记之三十三广义表实现二

33. 蛤蟆的数据结构笔记之三十三广义表实现二 本篇名言:" 希望是附丽于存在的,有存在,便有希望,有希望,便是光明.--鲁迅" 我们继续来看下广义表的其他代码实现.代码均来自网络,解释来自蛤蟆,均亲测可行. 欢迎转载,转载请标明出处: 1.  广义表实现二 1.1         main 创建两个链表的指针head和L. 输入一个字符串,调用GLCreate函数创建广义表.显示,获取头表,尾表,输出长度,深度,原子个数,复制列表,Merge列表,遍历,比较广义表操作. 如下图1:

javascript实现数据结构:广义表

原文:javascript实现数据结构:广义表  广义表是线性表的推广.广泛用于人工智能的表处理语言Lisp,把广义表作为基本的数据结构. 广义表一般记作: LS = (a1, a2, ..., an) LS是广义表的名称,n是它的长度,ai可以是单个元素,也可以是广义表,分别称为广义表LS的原子和子表.习惯上,用大写字母表示广义表的名称,小写字母表示原子.当广义表LS非空时,称第一个元素a1为LS的表头,称其余元素组成的表(a2, a3, ..., an)是LS的表尾. 下面列举一些广义表的例