廣義表的基本操作實現
阿新 • • 發佈:2019-02-10
廣義表的四個特徵:(1)廣義線性表;(2)元素複合性;(3)元素遞迴性;(4)元素共享性
廣義表的上述四個特徵對於他的使用價值和應用效果起到了很大的作用。廣義表的結構相當靈活,它可以相容線性表、陣列、樹和有向圖等各種常用的資料結構。當二維陣列的每行或每列作為子表處理時,二維陣列就是一個廣義表;如果限制廣義表中元素的共享和遞迴,廣義表和樹對應;如果限制廣義表的遞歸併允許資料共享,則廣義表和圖對應。
廣義表的基本操作有:(1)建立一個廣義表(我以頭尾連結串列作為儲存結構);(2)取表頭;(3)取表尾;(4)求廣義表深度;(5)求廣義表長度,(5)求廣義表原子個數;
(6)複製廣義表等。
現將完整程式碼粘在這兒,便於以後複習。(程式碼可能有些許錯誤,如看到,望指出,謝謝!)
(一)、儲存結構和函式定義(函式定義.h)
(二).函式實現(函式實現.cpp)#include<iostream> #include<stdio.h> using namespace std; #define MaxLength 60 typedef struct{ char str[MaxLength]; int length; }SString; typedef char AtomType; typedef enum{ ATOM, LIST } ElemTag;//ATOM=0,表示原子,LIST=1,表示子表 typedef struct Node { ElemTag tag; //標誌位tag用於區分元素是原子還是子表 union { AtomType atom; //AtomType是原子結點的值域,使用者自己定義型別 struct { struct Node *hp, *tp; //hp指向表頭,tp指向表尾 }ptr; }; }*GList, GLNode; //串函式定義 void StrAssign(SString *S, char cstr[]); //串賦值函式 int StrEmpty(SString S); //串判空函式 void StrCopy(SString *T, SString S); //串複製函式 void StrClear(SString *S); //串清空函式 int StrLength(SString S); //求串長函式 int StrCompare(SString S, SString T); //串比較函式 int StrInsert(SString *S, int pos, SString T);//串插入函式 int StrDelete(SString *S, int pos, int len); //串刪除函式 int StrCat(SString *T, SString S); //串連線函式 int StrIndex(SString S, int pos, SString T); //串定位函式 int StrReplace(SString *S, SString T, SString V);//串替換函式 void StrPrint(SString S); //串輸出函式 int SubString(SString *Sub, SString S, int pos, int len); //求子串函式 //廣義表函式定義 void Error(char *s); //錯誤處理函式 void CreateList(GList *L, SString S); //建立頭尾連結串列函式 void Init_GList(GList &GL); //初始化廣義表函式 void CopyList(GList *T, GList L); //複製廣義表函式 int GListLength(GList L); //求廣義表長度函式 int GListDepth(GList L); //求廣義表深度函式 int CountAtom(GList L); //求廣義表中原子結點的數目函式 void PrintGList(GList L); //遍歷輸出廣義表函式 void GetHead(GList L); //求廣義表表頭函式 void GetTail(GList L); //求廣義表表尾函式 void DistributeString(SString *Str, SString *HeadStr); //將非空字串str分割成兩部分:HSTR為第一個字元‘,’,之前的子串,SRE為之後的子串
(三)主函式測試(主函式測試.cpp)#include "stdafx.h" #include<iostream> #include<string> #include<stdio.h> #include"函式結構宣告.h" //串函式實現部分 //串賦值函式實現 void StrAssign(SString *S, char str[]) { int i; for (i = 0; str[i] != '\0'; i++) S->str[i] = str[i]; //將常量cstr中的字元賦值給串S S->length = i; } //判斷串是否為空,串為空返回1,否則返回0 int StrEmpty(SString S) { if (S.length == 0) return 1; else return 0; } //求串的長度操作 int StrLength(SString S) { return S.length; } //串的複製操作 void StrCopy(SString *T, SString S){ int i; for (i = 0; i<S.length; i++) //將串S的字元賦值給串T T->str[i] = S.str[i]; T->length = S.length; //將串S的長度賦值給串T } int StrCompare(SString S, SString T) { //串的比較操作 int i; for (i = 0; i<S.length&&i<T.length; i++)//比較兩個串中的字元 { if (S.str[i] != T.str[i]) //如果出現字元不同,則返回兩個字元的差值 return (S.str[i] - T.str[i]); } return (S.length - T.length); //如果比較完畢,返回兩個串的長度的差值 } int StrInsert(SString *S, int pos, SString T) {//串的插入操作。在S中第pos個位置插入T分為三種情況 int i; if (pos<0 || pos - 1>S->length){ //插入位置不正確,返回0 Error("插入位置不正確"); return 0; } if (S->length + T.length <= MaxLength){ //第一種情況,插入子串後串長≤MaxLength,即子串T完整地插入到串S中 for (i = S->length + T.length - 1; i >= pos + T.length - 1; i--) //在插入子串T前,將S中pos後的字元向後移動len個位置 S->str[i] = S->str[i - T.length]; for (i = 0; i<T.length; i++) //將串插入到S中 S->str[pos + i - 1] = T.str[i]; S->length = S->length + T.length; return 1; } else if (pos + T.length <= MaxLength){ //第二種情況,子串可以完全插入到S中,但是S中的字元將會被截掉 for (i = MaxLength - 1; i>T.length + pos - i; i--) //將S中pos以後的字元整體移動到陣列的最後 S->str[i] = S->str[i - T.length]; for (i = 0; i<T.length; i++) //將T插入到S中 S->str[i + pos - 1] = T.str[i]; S->length = MaxLength; return 0; } else{ //第三種情況,子串T不能被完全插入到S中,T中將會有字元被捨棄 for (i = 0; i<MaxLength - pos; i++) //將T直接插入到S中,插入之前不需要移動S中的字元 S->str[i + pos - 1] = T.str[i]; S->length = MaxLength; return 0; } } int StrDelete(SString *S, int pos, int len) {//在串S中刪除pos開始的len個字元 int i; if (pos<0 || len<0 || pos + len - 1>S->length){ Error("刪除位置不正確,引數len不合法"); return 0; } else{ for (i = pos + len; i <= S->length - 1; i++) S->str[i - len] = S->str[i]; S->length = S->length - len; return 1; } } //串的連線操作 int StrCat(SString *T, SString S) { int i, flag; if (T->length + S.length <= MaxLength){ for (i = T->length; i<T->length + S.length; i++) T->str[i] = S.str[i - T->length]; T->length = T->length + S.length; flag = 1; } else if (T->length<MaxLength){ for (i = T->length; i<MaxLength; i++) T->str[i] = S.str[i - T->length]; T->length = MaxLength; flag = 0; } return flag; } //擷取子串操作 int SubString(SString *Sub, SString S, int pos, int len) { int i; if (pos<0 || len<0 || pos + len - 1>S.length) { Error("引數pos和len不合法"); return 0; } else { for (i = 0; i<len; i++) Sub->str[i] = S.str[i + pos - 1]; Sub->length = len; return 1; } } //串的定位操作 int StrIndex(SString S, int pos, SString T) //BF演算法實現 { int i, j; if (StrEmpty(T)) return 0; i = pos; j = 0; while (i<S.length&&j<T.length){ if (S.str[i] == T.str[j]){ i++; j++; } else{ i = i - j + 1; j = 0; } } if (j >= T.length) return i - j + 1; else return 0; } //串的替換操作 int StrReplace(SString *S, SString T, SString V) { //將S中所有的T替換為V int i; int flag; if (StrEmpty(T)) return 0; i = 0; do{ i = StrIndex(*S, i, T);//找到T在S中的位置 if (i){ StrDelete(S, i, StrLength(T)); //刪除找到的T flag = StrInsert(S, i, V); //在i位置插入V if (!flag) return 0; i += StrLength(V); } } while (i); return 1; } //串的清空操作 void StrClear(SString *S){ S->length = 0; } //串的輸出操作 void StrPrint(SString S){ int i; for (i = 0; i<S.length; i++){ cout << S.str[i]; } cout << endl; } //廣義表函式實現部分 void Error(char *s) //錯誤處理函式 { cout << s << endl; exit(1); } void GetHead(GList L) //求廣義表的表頭結點操作 { if (L == NULL) Error("空表不能取表頭!"); GLNode *Head = L->ptr.hp; if (Head->tag == ATOM) cout << "表頭:" << Head->atom << endl; else { cout << "表頭:"; PrintGList(Head); cout << endl; } } void GetTail(GList L) //求廣義表的表尾操作 { if (L == NULL) Error("空表不能取表頭!"); GLNode *tail = L->ptr.tp; cout << "表尾:"; PrintGList(tail); cout << endl; } int GListLength(GList L) //求廣義表的長度操作 { int length = 0; GLNode *p = L; if (p == NULL) return 0; else { length = GListLength(p->ptr.tp); } return length + 1; } int GListDepth(GList L) //求廣義表的深度操作 { int max, depth; GLNode *p; if (!L) //如果廣義表非空,則返回1 return 1; if (L->tag == ATOM) //如果廣義表是原子,則返回0 return 0; for (max = 0, p = L; p; p = p->ptr.tp) //逐層處理廣義表 { depth = GListDepth(p->ptr.hp); if (max<depth) max = depth; } return (max + 1); } int CountAtom(GList L)//求廣義表中原子結點的數目,並返回 { int n1, n2; if (L == NULL) return 0; if (L->tag == ATOM) return 1; n1 = CountAtom(L->ptr.hp); //求表頭中的原子數目 n2 = CountAtom(L->ptr.tp); //求表尾中的原子數目 return (n1 + n2); } void CopyList(GList *T, GList L) //廣義表的複製操作。由廣義表L複製得到廣義表T { if (!L) //如果廣義表為空,則T為空表 *T = NULL; else { *T = (GList)malloc(sizeof(GLNode)); //表L不空,為T建立一個表結點 if (*T == NULL) Error("記憶體申請失敗!"); (*T)->tag = L->tag; if (L->tag == ATOM) //複製原子 (*T)->atom = L->atom; else //遞迴複製子表 { CopyList(&((*T)->ptr.hp), L->ptr.hp); CopyList(&((*T)->ptr.tp), L->ptr.tp); } } } void DistributeString(SString *Str, SString *HeadStr) //將串Str分離成兩個部分,HeadStr為第一個逗號之前的子串,Str為逗號後的子串 { int len, i, k; SString Ch, Ch1, Ch2, Ch3; len = StrLength(*Str); //len為Str的長度 StrAssign(&Ch1, ","); //將字元','、'('和')'分別賦給Ch1,Ch2和Ch3 StrAssign(&Ch2, "("); StrAssign(&Ch3, ")"); SubString(&Ch, *Str, 1, 1); //Ch儲存Str的第一個字元 for (i = 1, k = 0; i <= len&&StrCompare(Ch, Ch1) || k != 0; i++) //搜尋Str最外層的第一個括號 { SubString(&Ch, *Str, i, 1); //取出Str的第一個字元 if (!StrCompare(Ch, Ch2)) //如果第一個字元是'(',則令k加1 k++; else if (!StrCompare(Ch, Ch3)) //如果當前字元是')',則令k減去1 k--; } if (i <= len) //串Str中存在',',它是第i-1個字元 { SubString(HeadStr, *Str, 1, i - 2); //HeadStr儲存串Str','前的字元 SubString(Str, *Str, i, len - i + 1); //Str儲存串Str','後的字元 } else //串Str中不存在',' { StrCopy(HeadStr, *Str); //將串Str的內容複製到串HeadStr StrClear(Str); //清空串Str } } void CreateList(GList *L, SString S) //採用頭尾連結串列建立廣義表 { SString Sub, HeadSub, Empty; GList p, q; StrAssign(&Empty, "()"); if (!StrCompare(S, Empty)) //如果輸入的串是空串則建立一個空的廣義表 *L = NULL; else { if (!(*L = (GList)malloc(sizeof(GLNode)))) //為廣義表生成一個結點 Error("記憶體分配失敗!"); if (StrLength(S) == 1) //廣義表是原子,則將原子的值賦值給廣義表結點 { (*L)->tag = ATOM; (*L)->atom = S.str[0]; } else //如果是子表 { (*L)->tag = LIST; p = *L; SubString(&Sub, S, 2, StrLength(S) - 2); //將S去除最外層的括號,然後賦值給Sub do { DistributeString(&Sub, &HeadSub); //將Sub分離出表頭和表尾分別賦值給HeadSub和Sub CreateList(&(p->ptr.hp), HeadSub); //遞迴呼叫生成廣義表 q = p; if (!StrEmpty(Sub)) //如果表尾不空,則生成結點p,並將尾指標域指向p { if (!(p = (GLNode *)malloc(sizeof(GLNode)))) Error("記憶體分配失敗!"); p->tag = LIST; q->ptr.tp = p; } } while (!StrEmpty(Sub)); q->ptr.tp = NULL; } } } void PrintGList(GList L) //輸出廣義表的元素 { if (!L) cout << "()"; else { if (L->tag == ATOM) cout << L->atom; else { cout << '('; GLNode *p = L; while (p) { PrintGList(p->ptr.hp); p = p->ptr.tp; if (p) cout << ','; } cout << ')'; } } }
#include "stdafx.h"
#include<iostream>
#include<stdio.h>
#include"函式結構宣告.h"
int _tmain(int argc, _TCHAR* argv[])
{
GList L, T;
SString S;
char str[60];
int depth, length;
cout << "請輸入廣義表:" << endl;
cin >> str;
StrAssign(&S, str); //將字串賦值給串S
CreateList(&L, S); //由串建立廣義表L
cout << "輸出廣義表L中的元素:" << endl;
PrintGList(L); //輸出廣義表中的元素
cout << endl;
cout << "廣義表L表頭是:" << endl;
GetHead(L);
cout << "廣義表L表尾是:" << endl;
GetTail(L);
cout << "廣義表L中的原子數目是:" << CountAtom(L) << endl;
length = GListLength(L); //求廣義表的長度
cout << "廣義表L的長度:" << length << endl;
depth = GListDepth(L); //求廣義表的深度
cout << "廣義表L的深度:" << depth << endl;
CopyList(&T, L);
cout << "由廣義表L複製得到廣義表T廣義表T的元素為:" << endl;
PrintGList(T);
return 0;
}