(C语言!)广义表(头尾链表)的建立和输出

s

零零散散花了近半天的时间,查看各种资料,总算是完成了头尾链表存储结构的广义表的建立以及一种输出。

第一次写一篇文章记录一下此时的思路,唉,免不了过两天就忘了!

 ,首先,结构体的定义很常规。

typedef enum {ATOM,LIST} Elemtag;

typedef struct Glong {
    Elemtag tag;
    union {
        char atom;
        struct {
            struct Glong *hp,*tp;
        } htp;
    } un;
}*Glist;

这里懒得加注释了。

二,主程序框架

int main()
{
    Glist head;             /* 头节点指针 */
    fgets(str,100,stdin);   /* 输入的字符串 */
    head=Create(str);          /* Create函数为这个创建函数 */
    output(head);               /* 输出函数 */
    return 0;
}

三,广义表创建函数

Glist Create(char *str)
{
    Glist p;
    char s[3];
    s[0]='(',s[1]=')',s[2]='\0';
    if(Compare(str,s)==1) {                /* 比较是否为空表 */     
        return NULL;
    } else {
        p=(Glist)malloc(sizeof(struct Glong));          /* 无论后面是要表结点还是原子节点都要建立节点,所以在最前面建立,后面进行标识化 */
        if(str[0]>='a'&&str[0]<='z') {                  /* 如果是字母,说明是原子节点 */
            p->tag=ATOM;
            p->un.atom=str[0];
            return p;
        }
        if(str[0]=='(') {                               /* 如果有括号,结合前面非空表可知,此处一定不是空表,而且一定有一个表节点 */
            char *headstr,*tailstr;
            headstr=NULL,tailstr=NULL;                  /* 建立表头所依据的字符串   和  建立表尾所依据的字符串 */
            p->tag=LIST;
            Remove(str);                            /* 去点最外层括号,这样后面就方便得到headstr,tailstr了 */
            str++;                                  
            headstr=str;
            Divide(&tailstr,str);                           /* 因为不是空表,所以表头字符串一定存在,所以我只需要看表尾是否为空,这里如果没有表尾,我将其理解为空 */
                                                            /* 因为要改变tailstr的值所以用二重指针 */
            
            p->un.htp.hp=Create(headstr);                   /* 创建表头节点 */
            if(tailstr!=NULL) {
                addpar(tailstr);                            /* !!!!由于广义表定义上将除第一个元素外的其他元素看成一个表,称作表尾,但在形式上并没有最外层象征表的括号   */
                                                            /* 所以我表尾字符串加上最外层的括号 */
                tailstr--;
                p->un.htp.tp=Create(tailstr);               /* 建立表尾节点 */
            } else {
                p->un.htp.tp=NULL;
            }
        }
    }
    return p;
}

其中也用到一些辅助函数:

Remove函数

void Remove(char *sdr)          /* 去括号函数,即把括号换成字符# */
{
    int i,k;
    i=1,k=1;
    sdr[0]='#';
    while(sdr[i]!='\0') {
        if(sdr[i]=='(') {
            k++;
            i++;
            continue;
        }
        if(sdr[i]==')') {
            k--;
            if(k==0) {
                break;
            }
        }
        i++;
    }
    sdr[i]='#';
}

这里如果把最外层括号变为空字符的话,那么因为开头就是空字符,系统将此字符串视作空,不方便,而我只需要一个规定一个符号为逻辑上的空符即可。如果有uu们有好的解决办法,欢迎指教。

Divide函数,分离出表尾字符串的

void Divide(char **q,char *str)
{
    int i,k;
    i=0,k=0;
    while(str[k]!='\0'&&str[k]!='#') {
        if(str[k]=='(') {
            i++;
        }
        if(str[k]==')') {
            i--;
        }
        if(i==0&&str[k]==',') {
            str[k]='#';
            *q=str+k+1;
            break;
        }
        k++;
    }
}

至于为什么写Compare函数,是因为一时间解决不了strcmp函数参数要为字符串常量的问题

​
int Compare(char *str,char *st)
{
    int i=0;
    while(str[i]!='\0'&&st[i]!='\0')
    {
        if(str[i]>st[i])
        {
            return 0;
        }
        if(str[i]<st[i])
        {
            return 0;
        }
        i++;
    }
    if(str[i]=='\0'&&st[i]=='\0')
    {
        return 1;
    }else{
        return 0;
    }
}

​

最后一个加括号函数

void addpar(char *p)
{
    p--;
    p[0]='(';
    int i=1;
    while(p[i]!='#'&&p[i]!='\0') {
        i++;
    }
    p[i]=')';
}

输出的话一个递归就可以了

void output(Glist p)
{
    if(p!=NULL) {
        if(p->tag==LIST) {
            output(p->un.htp.hp);
            output(p->un.htp.tp);
        } else {
            printf("%c",p->un.atom);
            return;
        }
    }
}

四,举例验证此方法

        如果给定字符串为“(a,(b,c)) ”,那么进入程序

        非空表--------->>>>建立表结点1,字符串处理,去括号后为“   #a,(b,c)#   ”,str指针就指向a,

        分开后变成“  #a#(b,c)# ”,headstr指向a,tailstr指向第二个#

        然后递归调用自身建立原子节点a,结束此递归。

        给表尾字符串加括号变成“  #a((b,c))\0  ”,此时tailstr指针指向第一个(   。

        然后递归调用建立表尾节点2。

        字符串去括号    “ #a#(b,c)# ”                headstr指向第一个(           。

        表尾为空,那个就再递归建表头。

        有括号,建立表结点3。再去括号,有表头表尾,再递归建表头的原子节点b,而c要加上括号的。

        所以递归建表尾的时候又会有一个表结点。然后也是只有表头c,没有表尾。

         所以建表头的原子节点c。

        到此结束。

        不喜勿喷,有问题可以留言讨论。作者是个菜逼(先自报家门,事先申明)。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值