線性表是一種簡單的線性結構,特色是在非空的有限集合中,且第一個元素沒有直接前驅元素,最後一個元素沒有直接後繼元素,其餘元素都有惟一的前驅和後繼元素。線性表有順序存儲結構和鏈式存儲結構。node
指將線性表中的各個元素依次存放在一組地址連續的存儲單元中,一般將這種方法存儲的線性表稱爲順序表。
邏輯相鄰,物理存儲地址也相鄰數組
定義以下:markdown
/* ElemType類型根據實際狀況而定,這裏假設爲int */ typedef int ElemType; /* Status是函數的類型,其值是函數結果狀態代碼,如OK等 */ typedef int Status; /*線性結構使用順序表的方式存儲*/ //順序表結構設計 typedef struct { ElemType *data; int length; }Sqlist; 複製代碼
其中,ElemType表示數據元素類型,data用於存儲線性表中的數據元素的首地址,length用來表示線性表中數據元素的個數,Sqlist是結構體類型名。定義一個順序表代碼:Sqlist L; 指向順序表的指針:Sqlist *L;函數
Status InitList(Sqlist *L){ //爲順序表分配一個大小爲MAXSIZE 的數組空間 L->data = malloc(sizeof(ElemType) * MAXSIZE); // 存儲分配失敗退出 if(!L->data) exit(ERROR); // 初始化,空表長度爲0 L->length = 0; return OK; } 複製代碼
/* 初始條件:順序線性表L已存在,1≤i≤ListLength(L); 操做結果:在L中第i個位置以前插入新的數據元素e,L的長度加1 */ Status ListInsert(Sqlist *L,int i,ElemType e){ // i值不合法判斷 if((i<1) || (i>L->length+1)) return ERROR; // 存儲空間已滿 if(L->length == MAXSIZE) return ERROR; // 插入數據不在表尾,則先移動出空餘位置 if(i <= L->length){ for(int j = L->length-1; j>=i-1;j--){ //插入位置以及以後的位置後移動1位 L->data[j+1] = L->data[j]; } } // 將新元素e 放入第i個位置上 L->data[i-1] = e; // 長度+1; ++L->length; return OK; } 複製代碼
Status GetElem(Sqlist L,int i, ElemType *e){ //判斷i值是否合理, 若不合理,返回ERROR if(i<1 || i > L.length) return ERROR; //data[i-1]單元存儲第i個數據元素. *e = L.data[i-1]; return OK; } 複製代碼
int ListEmpty(Sqlist L){ if(L.length == 0) { return OK; } return ERROR; } 複製代碼
/* 初始條件:順序線性表L已存在,1≤i≤ListLength(L) 操做結果: 刪除L的第i個數據元素,L的長度減1 */ Status ListDelete(Sqlist *L,int i){ //線性表爲空 if(L->length == 0) return ERROR; //i值不合法判斷 if((i<1) || (i>L->length+1)) return ERROR; for(int j = i; j < L->length;j++){ //被刪除元素以後的元素向前移動 L->data[j-1] = L->data[j]; } //表長度-1; L->length --; return OK; } 複製代碼
*清空順序表性能
/* 初始條件:順序線性表L已存在。操做結果:將L重置爲空表 */ Status ClearList(Sqlist *L) { L->length=0; return OK; } 複製代碼
Status TraverseList(Sqlist L) { int i; for(i=0;i<L.length;i++) printf("%d\n",L.data[i]); printf("\n"); return OK; } 複製代碼
/* 初始條件:順序線性表L已存在 */ /* 操做結果:返回L中第1個與e知足關係的數據元素的位序。 */ /* 若這樣的數據元素不存在,則返回值爲0 */ int LocateElem(Sqlist L,ElemType e) { int i; if (L.length==0) return 0; for(i=0;i<L.length;i++) { if (L.data[i]==e) break; } if(i>=L.length) return 0; return i+1; } 複製代碼
在解決實際問題時,有時並不適合採用線性表的順序存儲結構,例如兩個一元多項式的相加、相乘,這就須要另外一種存儲結構——鏈式存儲。它是採用一組任意的連續或非連續存儲單元存儲線性表的元素。爲了表示每一個元素ai與其直接後繼ai+1的邏輯關係,鏈式存儲不只須要存儲元素自己,還要存儲一個指向其直接後繼元素的地址。這種存儲結構被稱之爲結點(node)。存儲元素的叫數據域,存儲地址的叫指針域。結點元素的邏輯順序稱之爲線性鏈表或單鏈表。spa
鏈式存儲最大的特色就是不連續的,因此每一個數據與數據之間的關係是經過指針域來進行鏈接的。設計
由於第一個結點沒有直接前驅結點,所以須要一個頭指針L指向它。爲了方便操做放在第一個元素結點以前一個結點稱之爲頭結點,頭指針變成指向頭結點,其數據域能夠存放如線表長度等信息,而指針域則存放第一個元素結點的地址信息。若該鏈表爲空,則頭結點指針域爲空。 最後一個元素沒有直接後繼元素,因此將其指針域設置爲「Null」空。指針
(圖片來自邏輯教育) code
便於首元結點處理和空表和⾮空表的統一處理orm
用C語言描述以下:
typedef struct Node{ ElemType data; struct Node *next; }Node; typedef struct Node * LinkList; 複製代碼
Status InitList(LinkList *L) { //產生頭結點,並使用L指向此頭結點 *L = (LinkList)malloc(sizeof(Node)); //存儲空間分配失敗 if(*L == NULL) return ERROR; //將頭結點的指針域置空 (*L)->next = NULL; return OK; } 複製代碼
/* 初始條件:順序線性表L已存在,1≤i≤ListLength(L); 操做結果:在L中第i個位置以後插入新的數據元素e,L的長度加1; */ Status ListInsert(LinkList *L,int i,ElemType e){ int j; LinkList p,s; p = *L; j = 1; //尋找第i-1個結點 while (p && j < i) { p = p-> next; ++j; } //第i個元素不存在 if(!p || j>i) return ERROR; //生成新結點s s = (LinkList)malloc(sizeof(Node)); //將e賦值給s的數值域 s->data = e; //將p的後繼結點賦值給s的後繼 s->next = p->next; //將s賦值給p的後繼 p->next = s; return OK; } 複製代碼
注意:須要先將p的next賦值給s的next,而後在將p的next指向s,若是操做反了,會形成p的next也就是圖中的Hank老師丟失,形成野指針。
/* 初始條件: 順序線性表L已存在,1≤i≤ListLength(L); 操做結果:用e返回L中第i個數據元素的值 */ Status GetElem(LinkList L,int i,ElemType *e){ // j: 計數. int j; // 聲明結點p; LinkList p; // 將結點p 指向鏈表L的第一個結點; p = L->next; // j計算=1; j = 1; // p不爲空,且計算j不等於i,則循環繼續 while (p && j < i) { //p指向下一個結點 p = p->next; ++j; } // 若是p爲空或者j>i,則返回error if(!p || j > i) return ERROR; // e = p所指的結點的data *e = p->data; return OK; } 複製代碼
/* 初始條件:順序線性表L已存在,1≤i≤ListLength(L) 操做結果:刪除L的第i個數據元素,並用e返回其值,L的長度減1 */ Status ListDelete(LinkList *L,int i,ElemType *e) { int j; LinkList p,q; p = (*L)->next; j = 1; // 查找第i-1個結點,p指向該結點 while (p->next && j< (i-1)) { p = p->next; ++j; } // 當i>n 或者 i<1 時,刪除位置不合理 if (!(p->next) || (j > i-1)) return ERROR; // q指向要刪除的結點 q = p->next; // 將q的後繼賦值給p的後繼 p->next = q->next; // 將q結點中的數據給e *e = q->data; // 讓系統回收此結點,釋放內存; free(q); return OK; } 複製代碼
Status ClearList(LinkList *L) { LinkList p,q; /* p指向第一個結點 */ p = (*L)->next; /* 沒到表尾 */ while(p) { q=p->next; free(p); p=q; } /* 頭結點指針域爲空 */ (*L)->next=NULL; return OK; } 複製代碼
/* 隨機產生n個元素值,創建帶表頭結點的單鏈線性表L(前插法)*/ void CreateListHead(LinkList *L, int n){ LinkList p; // 創建1個帶頭結點的單鏈表 *L = (LinkList)malloc(sizeof(Node)); (*L)->next = NULL; // 循環前插入隨機數據 for(int i = 0; i < n;i++) { //生成新結點 p = (LinkList)malloc(sizeof(Node)); //i賦值給新結點的data p->data = i; // p->next = 頭結點的L->next p->next = (*L)->next; //將結點P插入到頭結點以後; (*L)->next = p; } } 複製代碼
/* 隨機產生n個元素值,創建帶表頭結點的單鏈線性表L(後插法)*/ void CreateListTail(LinkList *L, int n){ LinkList p,r; // 創建1個帶頭結點的單鏈表 *L = (LinkList)malloc(sizeof(Node)); // r指向尾部的結點 r = *L; for (int i=0; i<n; i++) { // 生成新結點 p = (Node *)malloc(sizeof(Node)); p->data = i; // 將表尾終端結點的指針指向新結點 r->next = p; // 將當前的新結點定義爲表尾終端結點 r = p; } // 將尾指針的next = null r->next = NULL; } 複製代碼