資料結構——表,資料結構
資料結構——表
1、定義:
線性表是一個線性結構,它是一個含有n≥0個結點的有限序列,對於其中的結點,有且僅有一個開始結點沒有前驅但有一個後繼結點,有且僅有一個終端結點沒有後繼但有一個前驅結點,其它的結點都有且僅有一個前驅和一個後繼結點。
2、特徵/性質
1)集合中必存在唯一的一個第一個元素
2)集合中必存在唯一的一個最後元素
3)除最後一個元素之外,均有唯一的後繼
4)除第一個元素之外,均有唯一的前驅
3、線性表的基本操作
1)初始化線性表InitList(L)
2)銷毀線性表DestoryList(L)
3)清空線性表ClearList(L)
4)求線性表的長度ListLength(L)
5)判斷線性表是否為空白IsEmpty(L)
6)擷取線性表L中的某個資料元素內容GetElem(L,i,e)
7)檢索值為e的資料元素LocateElem(L,e)
8)返回線性表L中e的直接前驅元素PriorElem(L,e)
9)返回線性表L中e的直接後繼元素NextElem(L,e)
10)線上性表L中插入一個資料元素ListInsert(L,i,e)
11)刪除線性表L中第i個資料元素ListDelete(L,i,e)
4、線性表的順序表示:ArrayList
一般使用數組來描述 注意:數組中第i-1的單中繼存放區著線性表中第i個資料元素的內容,換句話說,C語言中數組的下標從“0”開始,如果L是順序表,則表中第i個資料元素是L.elem[i-1].
優點:在於隨機訪問元素 缺點:插入和刪除的時候,需要移動大量的元素
補充:線性表複雜操作
1、求線性表的並集
思路:擴大線性表LA,將存在於線性表LB中不存線上性表LA中的資料元素插入到線性表LA中去,只需要從線性表LB中依次去取的每個資料元素,並依值線上性表LA中進行查訪,如果不存在,則插入之
void union(List &La, List Lb){ La_len = ListLength(La); Lb_len = ListLength(Lb); for(i = 1;i <= Lb_len; i++) { GetElem(Lb, i, e);//取Lb中第i個資料元素賦給e if(!LocateElem(La,e,equal))//La中不存在和e相同的資料元素,則插之 ListInsert(La, ++La_len, e); }}
演算法複雜度:O(LALB)
2、線性表合并且按值非遞減有序排列
void MergeList(List La, List Lb, List &Lc){ //已知線性表La和Lb的資料元素按值非遞減排序 InitList(LC); i = j = 1;k = 0; La_len = ListLength(La); Lb_len = ListLength(Lb); while((i <= La_len) && (j <= Lb_len)) { GetElem(La, i, ai); GetElem(Lb, j, bj); if(ai <= bj) { ListInsert(Lc, ++k, ai); ++i; } else { ListInsert(Lc,++k, bj); ++j; } } while(i <= La_len) { GetElem(La,i++,ai); ListInsert(Lc, ++k, ai); } while(j <= Lb_len) { GetElem(Lb,j++,bj); ListInsert(Lc,++k,bj); }}
演算法複雜度:O(LA+LB)
參考代碼——典型作業碼實現
//數組定義 typedef struct { Elemtype elem[LIST_MAX_LENGTH]; //指向存放線性表中資料元素 int length; //線性表的當前長度 int listsize; }SEQLIST; //初始化線性表 int InitList(SEQLISI *L) { L.elem = (Elemtype *)malloc(LIST_MAX_LENGTH*sizeof(Elemtype));//分配空間 if(L.elem == NULL) exit(OVERFLOW);//儲存分配失敗 L.length = 0;//空表長度為0 L.listsize = LIST_MAX_LENGTH;//初始儲存容量 return OK; } //銷毀線性表 void DestoryList(SEQLIST *L) { if(L.elem) free(L.elem);//釋放線性表佔據的所有儲存空間 } //清空線性表 void ClearList(SEQLIST *L) { L.length = 0; } //求線性表的長度 int GetLength(SEQLIST L) { return(L.Length); } //判斷線性表是否為空白 int IsEmpty(SEQLIST L) { if(L.length == 0) return true; return false; } //擷取線性表L中某個資料元素的內容 int GetElem(SEQLIST L,int i,Elemtype *e) { if(i < 1 || i > L.Length) return error; *e = L.elem[i-1];//數組中第i-1個單中繼存放區著線性表中第i個資料元素內容 return ok; } //線上性表L中檢索值為e的資料元素 int LocateElem(SEQLIST L,Elemtype e) { for(i = 0;i < L.length;i++) if(L.elem[i] == e) return i+1; return 0; } //判定L中第一個與e滿足關係compare()的資料元素的位序,如果沒有,則返0 LocateElem(L,e, int (*compare)(ElemType, ElemType)) { i = 1;//i的初值為第一個元素的位序 p = L.elem; //p的初值為第一個元素的儲存位置 while(i<= L.length && !(*compare)(*p++,e)) ++i; if(i <= L.length)return i; else return 0; } //線上性表中第i個資料元素之前插入資料元素e int ListInsert(SEQLIST *L,int i,Elemtype e) { if(L.length >= L.listsize) exit(OVERFLOW); if(i < 1||i>L.length + 1) return error;//檢查i值是否合理 q = &(L.elem[i-1]); //q為插入的位置 for(p = L.elem[Length-1];p >= q;--p) { *(p+1) = *p; }//出入位置及之後的元素右邊移動 *q = e;//插入e L.length++; return ok; } //把線性表中第i個資料元素刪除 int ListDelete(SEQLIST *L, int i, Elemtype *e) { if(IsEmpty(L)) return error; if(i < 1 ||i>L.length) return error; p = &(L.elem[i-1]);//p為被刪除元素的位置 e = *p; //被刪除元素的值賦給e q = L.elem + L.length - 1; //表尾元素的位置 for(p = p+1;p <= q;++p) *(p-1) = *p;//被刪除元素之後的元素左移 --L.length; return OK; }
總結:順序儲存結構表示的線性表,在做插入或刪除操作的時,平均需要移動大約一半的資料元素;對於長度變化較大的線性表,要一次性地分配足夠的儲存空間,但這些空間常常又得不到充分的利用;線性表的容量難以擴充
補充:順序表的合并
void MergeList_Sq(SqList La, SqList Lb, SqList &Lc){ pa = La.elem;pb = Lb.elem; Lc.Listsize = Lc.length = La.length + Lb.length; pc = Lc.elem = (ElemType*)malloc(Lc.listsize * sizeof(ElemType)); if(!Lc.elem)exit(OVERFLOW); pa_last = La.elem + La.length - 1; pb_last = Lb.elem + Lb.length - 1; while(pa <= pa_last && pb <= pb_last) { if(*pa < *pb) *pc++ = *pa++; else *pc++ = *pb++; } //插入La剩餘元素 while(pa <= pa_last) *pc++ = *pa++;//插入La的剩餘元素 while(pb <= pb_last) *pc++ = *pb++;//插入Lb的剩餘元素}
演算法複雜度為O(La.length + Lb.length)
5、線性表的鏈表表示LinkedList
一般採用鏈表來描述
優點:對於新增和刪除操作add和remove方便,不需要移動元素 缺點:不方便隨機訪問元素,因為LinkedList要移動指標
常用術語:
1)表示每個資料元素的兩個部分資訊組合在一起叫做結點;
2)其中表示資料元素內容的部分叫做資料域data
3)表示直接後繼元素儲存地址的部分叫做指標或指標域next
4)head是頭指標,它指向單鏈表中第一個結點,這是單鏈表操作的進入點,最後一個結點沒有直接後續結點,所以放入NULL
5)為了簡化對鏈表的操作,常在鏈表的第一個結點之前附加入一個結點,並稱為頭結點
特徵:
1)線性表中的資料元素在儲存單元中的存放順序與邏輯順序不一定一致;用一組任意的儲存單中繼存放區線性表的資料元素(這組儲存單元可以是連續的,也可以是不連續的)
2)在對線性表操作時,只能通過頭指標進入鏈表,並通過每個結點的指標域向後掃描其餘結點,這樣就會造成尋找第一個結點和尋找最後一個結點所花費的時間不等,具有這種特點的存取方式被稱為順序存取方式。
參考代碼——典型操作實現
//實現線性表的鏈式儲存結構的類型的定義typedef struct linklist//結點類型{ Elemtype elem; struct linklist *next;}LINKLIST;typedef struct//鏈表類型{ LINKLIST *head;}LINK_LIST;//初始化鏈表int InitList(LINK_LIST *L){ L->head = (*LINKLIST)malloc(sizeof(LINKLIST));//為頭結點分配儲存單元 if(L->head) { L->head->next = NULL; return OK; } return error;}//摧毀鏈表void DestoryList(LINK_LIST *L){ LINKLIST *p; while(L->head)//依次刪除鏈表中的所有結點 { p = L->head; L->head = L->head->next; free(p); }}//清空鏈表void ClearList(LINK_LIST *L){ LINKLIST *p; while(L->head->next) { p = L->head->next; //p指向鏈表中頭結點後面的第一個結點 L->head->next = p->next;//刪除p結點 free(p);//釋放p結點佔據的儲存空間 }}//求鏈表的長度int ListLength(LINK_LIST L){ LINK_LIST *p; int len; for(p = L->head,len = 0;p->next == NULL; p=p->next,len++) return len;}//判斷鏈表是否為空白int IsEmpty(LINK_LIST L){ if(L->head->next == NULL) return true; return false;}//通過e返回鏈表L中第i個元素的內容int GetElem(LINK_LIST L, int i, Elemtype *e){ p = L->next; j = 1;//初始化,p指向第一個結點,j為計數器 while(p && j < i)//順時針向後尋找,直到p指向第i個元素或p為空白 { p = p->next; ++j; } if(!p || j > i) return ERROR; e = p->elem;//取第i個元素 return OK;}//演算法複雜度為O(n)//在鏈表L中檢索值為e的資料元素 LINKLIST *LocateELem(LINK_LIST L,Elemtype e) { LINKLIST *p; for(p = L->head->next; p&&p->elem != e; p=p->next); return(p); } //返回鏈表L中結點e的直接前驅結點 LINKLIST *PriorElem(LINK_LIST L,LINKLIST* e) { LINKLIST *P; if(L->head->next == e) return NULL;//檢測為第一個結點 for(p=L->head;p->next&&p->next != e;p = p->next); if(p->next == e) return p; return NULL; } //返回結點為e的直接後繼結點LINKLIST *NextElem(LINK_LIST L,LINKLIST* e){ LINKLIST *p; for(p=L->head->next;p&&p!=e;p=p->next); if(p) p=p->next; return p;}
補充:進階操作
1)插入結點
//在帶頭結點的單鏈線性表L中第i個位置之前插入元素e int ListInsert(LinkList *L,int i, ElemType) { p = L;j = 0; while(p && j<i-1) { p = p->next; ++j }//需找第i-1個結點 if(!p || j>i-1) return error;//i<1或者大於表長加1 s = (LinkList)malloc(sizeof(LNode)); s->data = e; s->next = p->next; p->next = s; return ok; }
複雜度為O(n)
2)刪除結點
//在帶頭結點的單鏈線性表L中刪除第i個元素,並由e返回其值int LisyDelete(LinkList *L, int i,ElemType &e){ p = L;j = 0; while(p->next && j < i-1) { p = p->next; ++j;//尋找第i個結點,並令p指向其前驅 } if(!(p->next) || j>i-1) return error; q = p->next; p->next = q->next; e = q->elem; free(q); return ok;}
複雜度為O(n)
3)合并有序鏈表
void MergeList_L(LinkList &La, LinkList &Lb, LinkList &Lc){ pa = La->next; pb = Lb->next; Lc = pc = La;//用La的頭結點作為Lc的頭結點 while(pa && pb)//由於鏈表的長度是隱藏的,修改迴圈條件 { if(pa->elem <= pb->elem) { pc->next = pa; //pc所指結點連結到pc所指結點之後 pc = pa; pa = pa->next; } else { pc->next = pb; pc = pb; pb = pb->next; } } pc->next = pa ? pa : pb; free(fb);}
6、迴圈鏈表
迴圈鏈表的操作和線性鏈表基本一致,差別在於演算法中迴圈條件不是p或p->next是否為空白了,而是它們是否等於頭指標。
7、雙向鏈表
資料結構順序表
不知道這個程式能不能滿足你的要求,該程式用順序表方式,能實現刪除線性表的元素,之後還可以往線性表中插入元素,後附有運行情況圖:
程式如下
#include<iostream>
using namespace std;
#include<malloc.h>
#define LIST_INIT_SIZE 100
#define LISTINCREMENT 10
#define OVERFLOW -1
#define OK 1
#define ERROR 0
typedef int Status;
typedef int ElemType;
typedef int KeyType;
typedef struct{
ElemType *elem;
KeyType *key;
int length;
int listsize;
}SqList;
typedef struct{
KeyType key;
}SElemType;
Status InitList (SqList &L){ /*定義一個線性表*/
int length1;
printf("請確定順序表的長度:");
scanf("%d",&length1);
L.listsize=length1;
L.elem=(ElemType*)malloc(length1*sizeof(ElemType));
if(!L.elem){
printf("out of space");
exit(OVERFLOW);
}
L.length=0;
return OK;
}
Status Listinsert (SqList &L,int i, ElemType e){ /*在i元素的前面插入元素e*/
ElemType *p,*q,*newbase;
if(i<1||i>L.length+1){
return ERROR;
}
if(L.length>L.listsize)
{
newbase=(ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
if (newbase==NULL){
printf("out of space");
return (OVERFLOW);
}
L.listsize+=LISTINCREMENT;
}
p=&( L.elem[i-1]);
for (q=&(L.elem[L.length-1]) ;q>=p;q--){
*(q+1)=*q;
}
L.elem[i-1]=e;
L.length++;
return OK;
}
Status DeleteList (SqList &L,int i){/*刪除i個元素*/
ElemType *q ,*p;
if(i<1||i>L.length){
return ERROR;
}
q = &(L.elem[i-1]);
p = L......餘下全文>>
資料結構 表
1。 不用管它;
2。 重不重複要看題目是怎麼要求的。