1. 程式人生 > >廣義表的複製及C語言程式碼實現

廣義表的複製及C語言程式碼實現

對於任意一個非空廣義表來說,都是由兩部分組成:表頭和表尾。反之,只要確定的一個廣義表的表頭和表尾,那麼這個廣義表就可以唯一確定下來。

複製一個廣義表,也是不斷的複製表頭和表尾的過程。如果表頭或者表尾同樣是一個廣義表,依舊複製其表頭和表尾。

所以,複製廣義表的過程,其實就是不斷的遞迴,複製廣義表中表頭和表尾的過程。

遞迴的出口有兩個:
  1. 如果當前遍歷的資料元素為空表,則直接返回空表。
  2. 如果當前遍歷的資料元素為該表的一個原子,那麼直接複製,返回即可。

還拿廣義表C為例:
圖1 廣義表C的結構示意圖
程式碼實現:
#include <stdio.h>
#include <stdlib.h>

typedef struct GLNode{
    int tag;//標誌域
    union{
        char atom;//原子結點的值域
        struct{
            struct GLNode * hp,*tp;
        }ptr;//子表結點的指標域,hp指向表頭;tp指向表尾
    };
}*Glist,GNode;

Glist creatGlist(Glist C){
    //廣義表C
    C=(Glist)malloc(sizeof(GNode));
    C->tag=1;
    //表頭原子‘a’
    C->ptr.hp=(Glist)malloc(sizeof(GNode));
    C->ptr.hp->tag=0;
    C->ptr.hp->atom='a';
    //表尾子表(b,c,d),是一個整體
    C->ptr.tp=(Glist)malloc(sizeof(GNode));
    C->ptr.tp->tag=1;
    C->ptr.tp->ptr.hp=(Glist)malloc(sizeof(GNode));
    C->ptr.tp->ptr.tp=NULL;
    //開始存放下一個資料元素(b,c,d),表頭為‘b’,表尾為(c,d)
    C->ptr.tp->ptr.hp->tag=1;
    C->ptr.tp->ptr.hp->ptr.hp=(Glist)malloc(sizeof(GNode));
    C->ptr.tp->ptr.hp->ptr.hp->tag=0;
    C->ptr.tp->ptr.hp->ptr.hp->atom='b';
    C->ptr.tp->ptr.hp->ptr.tp=(Glist)malloc(sizeof(GNode));
    //存放子表(c,d),表頭為c,表尾為d
    C->ptr.tp->ptr.hp->ptr.tp->tag=1;
    C->ptr.tp->ptr.hp->ptr.tp->ptr.hp=(Glist)malloc(sizeof(GNode));
    C->ptr.tp->ptr.hp->ptr.tp->ptr.hp->tag=0;
    C->ptr.tp->ptr.hp->ptr.tp->ptr.hp->atom='c';
    C->ptr.tp->ptr.hp->ptr.tp->ptr.tp=(Glist)malloc(sizeof(GNode));
    //存放表尾d
    C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->tag=1;
    C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp=(Glist)malloc(sizeof(GNode));
    C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->tag=0;
    C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.hp->atom='d';
    C->ptr.tp->ptr.hp->ptr.tp->ptr.tp->ptr.tp=NULL;
    return C;
}
void copyGlist(Glist C, Glist *T){
    //如果C為空表,那麼複製表直接為空表 
    if (!C) {
        *T=NULL;
    }
    else{
        *T=(Glist)malloc(sizeof(GNode));//C不是空表,給T申請記憶體空間
        //申請失敗,程式停止
        if (!*T) {
            exit(0);
        }
        (*T)->tag=C->tag;//複製表C的tag值
        //判斷當前表元素是否為原子,如果是,直接複製
        if (C->tag==0) {
            (*T)->atom=C->atom;
        }else{//執行到這,說明覆制的是子表
            copyGlist(C->ptr.hp, &((*T)->ptr.hp));//複製表頭
            copyGlist(C->ptr.tp, &((*T)->ptr.tp));//複製表尾
        }
    }
}
int main(int argc, const char * argv[]) {
    Glist C=NULL;
    C=creatGlist(C);
    Glist T=NULL;
    copyGlist(C,&T);
    printf("%c",T->ptr.hp->atom);
    return 0;
}
執行結果: a

總結

在實現複製廣義表的過程中,實現函式為: void copyGlist(Glist C, Glist *T); 其中,Glist *T,等同於: struct GLNode* *T,此為二級指標,不是一級指標。在主函式中,呼叫此函式時,傳入的是指標 T 的地址,而不是 T 。

這裡使用的是地址傳遞,而不是值傳遞。如果在這裡使用值傳遞,會導致廣義表 T 丟失結點,複製失敗。