郑州经济技术开发区官网/如何做网站关键词优化
很久没有发博客记录了,不过应该也没人关心这个,哈哈哈。
突然想起来,学习也不能只是干学,稍微做点记录。
之前我对html、css、js基础有了一定的理解,也学了一些模板,不过现在我想先把计算机基础给补上,所以把数据结构理一理!
近在学习数据结构C语言版,有一些心得,跟大家分享一下
可能会有很多比较基础的知识,大佬勿喷!
ok,我现在在学习广义表的结构,前边学的其他存储结构我后边会再整理一下。下边是我对广义表的一些理解,大家可以适当的参考一下,如果方便的话,也麻烦帮我指出不足之处,给我这个想要继续往上的学习者一点反馈!
数据结构C语言——广义表
广义表(Generalized List)
下边我就一般用L表示广义表
基本定义我就不多写了,网上已经有很多了,大家可以上网自行搜索
一、基本概念
L=(a1,a2,a3,……);
a1可以是不可再分的元素,就是原子;也可以是可以再分的子表;
L1=(a1,a2,a3,a4,a5,a6);
- 表头:对于非空的广义表,第一个元素就是表头元素,就像上边的a1,就是广义表L1的表头元素;
- 表尾:对于L1来说,表尾元素就是除了a1外的全部元素组成的元素序列(a2,a3,a4,a5,a6),是L1的一个子表;
- 长度:就是广义表的元素个数,L1长度为6;
- 深度:广义表里嵌套的最大层数,简单来说就是所有原子元素套的括号层数最多的,那个层数就是这里所说的深度;
二、实现
1、准备工作
把那些数字用一些有含义的符号表示可读性好点
#include<stdio.h>
#include<stdlib.h>#define TRUE 1
#define FALSE 0
#define OVERFLOW -1
#define ERROR 0
#define OK 1
typedef int Status;
typedef int ElemType;
typedef char AtomType;
2、广义表的定义
typedef enum{ATOM,LIST//这个相当于是一个集合,ElemTag类型的元素可以等于这两个属性
}ElemTag;
typedef struct GLNode{ElemTag tag;//区分原子结点、表结点union{AtomType atom;//tag==ATOM时,atom存放原子结点值struct{//tag==LIST时,表示是子表struct GLNode *hp;struct GLNode *tp;}ptr;//表结点的指针域,ptr.hp指向表头,ptr.tp指向表尾}un;
}GLNode,*GList;//广义表
3、函数声明
void InitGList(GList &L);//创建一个原子结点e
void CreatGList(GList &c,char ch);//创建一个长度为2的广义表,表头是原子结点,值为ch
GLNode *MakeAtom(AtomType e);//创建原子结点
Status GListEmpty(GList L);//判断广义表L是否为空
Status InsertHead(GList &L,GLNode *p);//在广义表L的表头插入p元素
int GListLength(GList L);//求广义表L的长度
Status InsertTail(GList &L,GLNode *p);//在广义表L的表尾添加新的结点
int CopyGList(GList &T,GList L);//由广义表L复制得到广义表T
GLNode *GetHead(GList L);//获取广义表L的表头
GLNode *GetTail(GList L);//获取广义表L的表尾(第一层的尾结点)
GLNode *GetTail1(GList L);//获取广义表L的表尾(最底层的尾结点)
Status DeleteHead(GList &L,GList &p);//删除一个广义表L的表头,把删除的表头保存在p中
int GListDepth(GList L);//求广义表L的深度
void visit(AtomType e);//遍历函数
Status GListTraverse(GList &L,void(*visit)(AtomType e));//广义表的遍历
4、创建一个空的广义表
void InitGList(GList &L){L = NULL;
}
5、创建一个长度为2的广义表,表头是原子结点,值为ch,表尾是一个空的子表
很笨的一个方法,应该还有更简便的,我再试试看
void CreatGList(GList &c,char ch){c=(GList)malloc(sizeof(GList));c->tag=LIST;c->un.ptr.hp=(GList)malloc(sizeof(GList));c->un.ptr.hp->tag=ATOM;c->un.ptr.hp->un.atom=ch;c->un.ptr.tp=(GList)malloc(sizeof(GList));c->un.ptr.tp->tag=LIST;c->un.ptr.tp->un.ptr.hp=(GList)malloc(sizeof(GList));c->un.ptr.tp->un.ptr.tp=NULL;
}
6、创建一个原子结点
GLNode *MakeAtom(AtomType e){GLNode *p;p=(GList)malloc(sizeof(GLNode));//分配空间if(p==NULL)return NULL;//分配空间失败,可能是缓存不足p->tag=ATOM;p->un.atom=e;return p;
}
7、判断广义表L是否为空
Status GListEmpty(GList L){if(L==NULL)return 1;return 0;
}
8、在广义表L的表头插入p元素
/Status InsertHead(GList &L,GLNode *p){p->tag=LIST;p->un.ptr.hp=p;p->un.ptr.tp=L;L=p;return OK;
}
9、求广义表L的长度
int GListLength(GList L){int len = 0;if(NULL==L)return 0;if(L->tag == ATOM)return 1;while(L!=NULL){L = L->un.ptr.tp; len++;}return len;
}
10、在广义表L的表尾添加新的结点
Status InsertTail(GList &L,GLNode *p){GLNode *q;GList tail;tail=(GList)malloc(sizeof(GLNode));if(NULL==tail)return OVERFLOW;tail->tag=LIST;tail->un.ptr.hp=p;tail->un.ptr.tp=NULL;if(NULL==L)L=tail;else{for(q=L;q->un.ptr.tp!=NULL;q=q->un.ptr.tp);//定位到最后一个结点q->un.ptr.tp=tail;}return OK;
}
11、由广义表L复制得到广义表T
int CopyGList(GList &T,GList L){if(L==NULL)T=NULL;else{T=new GLNode;//新建一个GLNode结点if(T==NULL)return OVERFLOW;//创建失败,可能是缓存不足T->tag = L->tag;//创建成功if(L->tag == ATOM)T->un.atom = L->un.atom;//是原子结点的话,复制else{//是子表结点的话,继续调用,往下找原子结点。//这玩意是递归,我调用我自己CopyGList(T->un.ptr.hp, L->un.ptr.tp);CopyGList(T->un.ptr.tp, L->un.ptr.tp);}}return OK;
}
12、获取广义表L的表头
GLNode *GetHead(GList L){GList p;InitGList(p);if (GListEmpty(L))return NULL;else{p=new GLNode;//新建一个表结点出来,在L上操作会影响到后边的操作p->tag = L->un.ptr.hp->tag;p->un.ptr.tp = NULL;if (p->tag == ATOM)p->un.atom = L->un.ptr.hp->un.atom;//把表头的原子值保存到p中else//把L的表头保存在p的表头处p->un.ptr.hp=L->un.ptr.hp;return p;}
}
13、获取广义表L的表尾(第一层的尾结点)
//下边两个,我也不太清楚怎么说,反正需要那个节点就用那个函数吧
//各取所需,不冲突
GLNode *GetTail(GList L){if(L==NULL)return NULL;return L->un.ptr.tp;
}GLNode *GetTail1(GList L){GLNode *p;if(L==NULL)return NULL;for(p=L;p->un.ptr.tp!=NULL;p=p->un.ptr.tp);//p的的尾指针为NULL时,p就是这个广义表的尾结点return p;
}
14、求广义表L的深度
int GListDepth(GList L){int d;GLNode *p;if(L==NULL)return 1;//空结点if(L->tag==ATOM)return 0;//原子结点for(p=L;p!=NULL;p=p->un.ptr.tp){//有点笨的方法,本来两个递归就行,但是没成功,先用这个看看吧,也还行d=GListDepth(p->un.ptr.hp)+1;if(d>0)return d+1;}
}
15、广义表的遍历
void visit(AtomType e){//简单的输出函数,如果觉得麻烦也可以不用函数printf("%c ",e);
}Status GListTraverse(GList &L,void(*visit)(AtomType e)){if(L==NULL)return NULL;if(L->tag==ATOM)visit(L->un.atom);else{GListTraverse(L->un.ptr.hp,visit);GListTraverse(L->un.ptr.tp,visit);}return OK;
}
16、主函数(测试)
这是我测试函数是否可以正常使用的程序
如果函数都懂了的话,可以看一下这个程序,看看具体怎么把函数的功能与数据结合,我个人感觉这是学编程最重要的。
void main(){GLNode *p,*q,*pp,*qq,*ppp,*qqq;AtomType a,b,c;int i,j,k,ii,jj,kk,iii,jjj,kkk;InitGList(p);InitGList(q);InitGList(pp);InitGList(qq);//这一步加不加无所谓,后台运行的时候好像是会自动初始化的printf("输入表长为2的广义表A第一个原子结点的值(一个字符):");scanf("%c",&a);CreatGList(p,a);if(!GListEmpty(p))printf("操作成功\n\n");printf("是否创建一个原子结点B(是1否0)\n\n");scanf("%d",&i);if(i){q=MakeAtom('b');if(!GListEmpty(q))printf("创建成功\n\n");printf("原子结点值为:%c\n\n",q->un.atom);}printf("是否遍历原子结点B(是1否0)\n\n");scanf("%d",&j);if(j){GListTraverse(q,visit);}printf("是否查看广义表A的深度(是1否0)\n\n");scanf("%d",&k);if(k){printf("广义表A的深度为:%d\n\n",GListDepth(p));}printf("是否将原子结点B插入到广义表A表头前(是1否0)\n\n");scanf("%d",&ii);if(ii){InsertHead(p,q);printf("操作成功\n\n");printf("广义表的长度为:%d\n\n",GListLength(p));}printf("是否将原子结点B插入到广义表A表尾后(是1否0)\n\n");scanf("%d",&jj);if(jj){InsertTail(p,q);printf("操作成功\n\n");printf("广义表的长度为:%d\n\n",GListLength(p));}printf("是否获取广义表A的表头结点(是1否0)\n\n");scanf("%d",&kk);if(kk){printf("pp原来的长度为:%d\n\n",GListLength(pp));pp=GetHead(p);if(!GListEmpty(pp))printf("操作成功,表头结点保存在pp结点中\n\n");printf("pp现在的长度为:%d\n\n",GListLength(pp));}printf("是否获取广义表A的表尾结点(是1否0)\n\n");scanf("%d",&iii);if(iii){printf("qq原来的长度为:%d\n\n",GListLength(qq));qq=GetTail(p);if(!GListEmpty(qq))printf("操作成功,表头结点保存在qq结点中\n\n");printf("qq现在的长度为:%d\n\n",GListLength(qq));}printf("是否删除广义表A的表头结点(是1否0)\n\n");scanf("%d",&jjj);if(jjj){DeleteHead(p,ppp);if(!GListEmpty(ppp))printf("操作成功,删除的表头结点保存在ppp结点中\n\n");printf("ppp结点的长度为:%d\n\n",GListLength(ppp));}
}
17、下边是运行结果
因为是自己瞎编的,所以看起来效果可能一般,将就着看看,认真看还是有点东西的
18、体会
我差不多把每个函数的实现都用空行隔开了,你们可以尝试一个一个把程序编出来,自己实现的感觉真的真的很不一样,很奇妙的感觉,我喜欢编程,有一部分原因就是因为这个感觉。
不要嫌太乱了,真正严谨的语句我现在还不懂,再给我一丢丢时间,我会加油的!
PS:对了,广义表还有另外一种结构,顺序结构,我上边用的是链式结构,顺序结构我在网上看了一些大牛发的文章,有兴趣的话可以去看看,这是我觉得不错的一篇文章,看起来不会特别吃力,想学好就耐心一点
各位,一起加油吧!fighting!
广义表顺序存储:https://blog.csdn.net/weixin_33917663/article/details/112541429
温馨提示:
没有实现的程序,大家看完之后可以试着自己去写,一个一个函数来,就像我上边那样,当然如果你有更好的方法,欢迎给我一点反馈。
以上内容不一定完全对,但是错的应该就是一些小细节,之后如果我找到了,我会及时修改的,请大家多多包涵!