1.定義:廣義表是一種復雜的數據結構,是線性表的擴展,能夠表示樹結構和圖結構。
2.細分定義:廣義表是n個數據元素a0,a1,...,an-1組成的有限序列,記為
GList=(a0,a1,...,an-1)
其中,
(1)ai或為不可分的數據元素(稱為原子),或為可再分的廣義表(稱為子表)。
(2)廣義表的元素個數n稱為廣義表長度(特殊:當n=0時,為空表。)
(3)廣義表的深度是指表格中所含括號的層數(特殊:原子的深度為0,空表的深度為1.)
注意:如果廣義表作為自身的一個元素,則稱該廣義表為遞歸表。遞歸的深度是無窮指,其長度是有限值。
(4)為了區分原子和表,約定大寫字母表示表,小寫字母表示原子。
(5)另一種廣義表表示稱為又名表,約定每個表都要有名稱,將名稱寫在表組成的括號前。
(6)廣義表的語法:其中“()”作為廣義表開始和結束的標記,“,”作為原子或子表的分隔符。
3.廣義表的特性。
(1)線性結構。(廣義表是一種線性結構,數據元素之間是線性關系,只不過元素不一定都是原子了,
如果元素都是原子,那么這個廣義表就是線性表,所以說線性表是廣義表的特例)
(2)多層次結構,有深度。(注意:廣義表是樹的擴展。當限制表中成分不能共享和遞歸時,該廣義樹
就是樹,樹中的葉子結點對應廣義表中的原子,非葉結點對應子表)
(3)可共享(一個廣義表可作為其他廣義表的子表,多個廣義表可共享一些廣義表。
(4)可遞歸(廣義表是一個遞歸表,當廣義表中有共享或遞歸成分的子表時構成圖結構,與有根,有序,有向圖對應。
4.廣義表的圖形表示
a.說明:
(1)當廣義表L(a,b)的數據元素全部都是原子時,L為線性結構的線性表。
(2)當廣義表L(c,L)的數據元素中有子表,但沒有共享和遞歸成分時,T為樹結構的純表。
(3)當廣義表L(d,L,T)的數據元素中有子表,並且有共享成分時,G為結構的再入表。
(4)當廣義表L(e,Z)的數據元素中有子表且有遞歸成分時,Z為圖結構的遞歸表。
5.廣義表的抽象數據類型
a.廣義表的操作主要有:
(1)創建廣義表
(2)判斷廣義表是否為空表
(3)遍歷廣義表
(4)求廣義表長度和深度
(5)插入和刪除數據元素
(6)查找指定原子所在結點
(7)比較廣義表是否相等
(8)復制廣義表等
b.廣義表接口GGenList
public interface GGenList<T>
{
boolean isEmpty(); //判斷廣義表是否為空
int length(); //返回廣義表長度
int depth(); //返回廣義表深度
GenListNode<T> insert(int i,T x); //返回原子x作為第i個元素
GenListNode<T> insert(int i,GenList<T> glist);//插入子表作為第i個元素
void remove(int i); //刪除第i個元素
}
6.廣義表的存儲結構
a.廣義表的單鏈表示
結點說明:其有三個域組成,分別為如下:
atom:其是一個標志位,表示該元素是否為原子,atom=1,為原子。atom=0,為子表。
data:當atom=1,data域的保存原子信息,atom=0,data域保存子表的第一個結點地址。
next:保存后繼結點地址,若沒有后繼元素,next=null。
b.廣義表的雙鏈表示
結點說明:其有三個域組成,分別為如下:
data:數據,可為原子,也可為子表
child:只當data為原子,child為null。
next:保存后繼結點地址,若沒有后繼元素,next=null。
注意:廣義表的雙鏈表示必須帶頭結點,否則對共享子表進行頭插入和頭刪除操作將產生錯誤。
c.廣義表的雙鏈表示的實現
(1).廣義表雙鏈表示的結點類
public class GenListNode<T>
{
public T data; //數據域
public GenList<T> child; //地址域,指向子表
public GenListNode<T> next; //地址域,指向后繼結點
// 構造結點,data指定元素,child指向子表,next指向后繼結點
public GenListNode(T data,GenList<T> child,GenListNode<T> next)
{
this.data=data;
this.child=child;
this.next=next;
}
public GenListNode(T data){ this(data,null,null);}
//構造頭結點
public GenListNode(){ this(null,null,null);}
}
(2)雙鏈表示的廣義表類
public class GenList<T> //雙鏈表示的廣義表類
{
public GenListNode<T> head; //頭指針,指向頭結點
//構造空廣義表。創建頭結點,三個域值都為null
public GenList(){ head=new GenListNode<T>();}
public GenList(T[] atoms)//構造廣義表,由數組提供原子初值,算法同單鏈表,方法體暫忽略
//判斷廣義表是否空
public boolean isEmpty(){ return head.next==null;}
public int length() //返回廣義表長度,算法同單鏈表,方法體暫忽略
public String toString(){ return this.toString("");} //返回廣義表所有元素的描述字符串
//返回廣義表所有元素值對應的字符串,形式為"(,)",廣義表遍歷算法,遞歸算法
public String toString(String str)
{
str+="(";
GenListNode<T> p=this.head.next;
while(p!=null)
{
if(p.child==null)
str+=p.data.toString();
else{ str.child.toString(); //遞歸調用,遍歷子表添加子表描述字符串
if(p.next!=null)
str+=",";
p=p.next;
}
return str+")"; //如果是空表,只返回()
}
public int depth() //返回廣義表深度,遞歸方法
{
int max=1;
GenListNode<T> p=this.head.next;
while(p!=null)
{
if(p.child!=null)
{
int d=p.child.depth(); //遞歸調用,返回子表深度
if(max<=d) //記住最大子表深度
{ max=d+1 ;//當前廣義表深度為子表深度加一
}
p=p.next;
}
return max;
}
//插入原子作為第i個元素,算法同單鏈表,方法體暫忽略
public GenListNode<T> insert(int i,T x)
public GenListNode<T> insert(int i,GenList<T> glist) //插入子表作為第i個元素
{
if(glist==null)
return null; //不能插入空對象
GenListNode<T> p=this.head;
for(int j=0;p.next!=null&&j<i;j++){
p=p.next;
}
p.next=new GenListNode<T>(null,glist,p.next);
return p.next;
}
//廣義表最后添加原子結點,算法同單鏈表
public void append(T x){
while(p.next!=null){
p=p.next;
}
p.next=new GenListNode<T>(x,null,null);
}
//在廣義表最后添加子表
public void append(GenList<T> glist){
insert(integer.MAX_VALUE,glist); }
}
(3)由原子數組構造廣義表。
public class GenList_ex
{
public static void main(String[] args)
{
String[] glist={"b","c","e"};
GenList<String> glist1=new Genlist<String>(glist); //由原子數組構造廣義表
glist1.insert(0,"a"); //頭插入原子
glist1.insert(3,"d"); //中間插入
glist.append("f"); //尾插入
}
(4)由廣義表表示創建廣義表
public class GenList_String
{
private static int i=0;
public static GenList<String> createGenList(String gliststr)
{
i++; //跳過‘(’
GenList<String> glist=new GenList<String>(); //構造空廣義表,只有頭結點
GenListNode<String> p=glist.head; //指向頭結點
while(i<gliststr.length())
{
char ch=gilststr.charAt(i);
switch(ch)
{
case ',':i++;
break;
case '(':
{
p.next=new GenListNode<String>(); //創建子表結點
p=p.next;
p.child=create(gliststr); //創建子表,遞歸調用
break;
}
case ')':i++;
return gilst;
default : //字符串表示原子
{
int j=i+1;
ch=gliststr.charAt(j);
while(ch!='('&&ch!=','&&ch!=')')
{
j++;
ch=gliststr.charAt(j);
}
p.next=new GenListNode<String>(gilststr.substring(i,j)); //創建結點
p=p.next;
i=j;
}
}
}return null;
}