广义表,相对于链表较复杂,相对于树又较简单....用来过渡顺序表和树是非常好的选择.
废话不多说,一言不合就贴代码.
/*
*文件说明:广义表相关声明及定义
*作者:高小调
*日期:2016-12-12
*集成开发环境:Microsoft Visual Studio 2010
*/
#ifndef __GENERALLIST_H__
#define __GENERALLIST_H__
#include
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<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<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(MaxDepthnext;
}
return MaxDepth; //返回最大深度
}
private:
Node * _head;
};
#endif
/*
*文件说明:测试文件
*作者:高小调
*日期:2016-12-12
*集成开发环境:Microsoft Visual Studio 2010
*/
#include
using namespace std;
#include"GeneralList.h"
void GeneralListTest(){
const char * const str1 = "(a)";
GeneralList g1(str1);
g1.Print();
cout<<"Size = "<
总结:
第一次接触这个,还确实有点难办,写得我脑袋都透支了,还专门打了几把LOL休息了一下....
这个东西并不是有多难,仅仅是因为递归程序,极其难于调试.当程序出问题时,调试比较让人抓狂!
还有一点就是,个人太钻牛角尖.有时候及时接受别人的知识,然后纳入自己的知识体系,比自己死磕要快得多....