**線性表:**由n個數據特性相同的元素構成的有限序列,有順序存儲和鏈式存儲兩種表示形式。 算法
空表:線性表中元素的個數n=0的表。spa
線性表的鏈式存儲結構:特色是用一組任意的存儲單元存儲線性表的數據元素,包括兩個域,其中存儲數據元素信息的域稱爲數據域,存儲直接後繼存儲位置的域稱爲指針域。3d
循環單鏈表:是另外一種形式的鏈式存儲結構。它的特色是表中最後一個結點的指針域指向頭結點,整個鏈表造成一個環。 指針
循環雙鏈表:是另外一種形式的鏈式存儲結構。它的特色是表中最後一個結點的指針域指向頭結點,頭節點同時指向最後一個節點,整個鏈表造成一個環。(這個圖畫的太醜啦!!)code
雙向鏈表:是指有兩個指針域,其一指向直接後繼,另外一指向直接前趨。 blog
線性結構:若結構是非空有限集,則有且僅有一個開始結點和一個終端結點,而且全部結點都最多隻有一個直接前趨和一個直接後繼。it
非空線性表或線性結構特色: 1.存在惟一的一個被稱做「第一個」的數據元素;2.存在惟一的一個被稱做「最後一個」的數據元素;3.除第一個以外,結構中的每一個數據元素均只有一個前驅;4.除最後一個以外,結構中的每一個數據元素均只有一個後繼io
(一)利用數據元素的存儲位置表示線性表中相鄰數據元素之間的先後關係,即線性表的邏輯結構與存儲結構一致 (二)在訪問線性表時,能夠快速地計算出任何一個數據元素的存儲地址。所以能夠粗略地認爲,訪問每一個元素所花時間相等思維導圖
這種存取元素的方法被稱爲隨機存取法class
優勢: 存儲密度大(結點自己所佔存儲量/結點結構所佔存儲量);能夠隨機存取表中任一元素
缺點:在插入、刪除某一元素時,須要移動大量元素;浪費存儲空間;屬於靜態存儲形式,數據元素的個數不能自由擴充。
爲了克服這樣的缺點---鏈表
鏈表各結點由兩個域組成:數據域:存儲元素數值數據;指針域:存儲直接後繼結點的存儲位置
**頭指針:**指向鏈表中第一個結點的指針
**頭結點:**在鏈表的首元結點以前附設的一個結點;數據域內只放空表標誌和表長等信息
**首元結點:**指鏈表中存儲第一個數據元素a1的結點
鏈表中設置頭結點的好處:
⒈便於首元結點的處理 首元結點的地址保存在頭結點的指針域中,因此在鏈表的第一個位置上的操做和其它位置一致,無須進行特殊處理;
⒉便於空表和非空表的統一處理 不管鏈表是否爲空,頭指針都是指向頭結點的非空指針,所以空表和非空表的處理也就統一了。 頭結點的數據域能夠爲空,也可存放線性表長度等附加信息,但此結點不能計入鏈表長度值。
(一)結點在存儲器中的位置是任意的,即邏輯上相鄰的數據元素在物理上不必定相鄰 (二)訪問時只能經過頭指針進入鏈表,並經過每一個結點的指針域向後掃描其他結點,因此尋找第一個結點和最後一個結點所花費的時間不等
這種存取元素的方法被稱爲順序存取法
優勢: 存儲密度小(結點自己所佔存儲量/結點結構所佔存儲量);刪除或者插入操做時間複雜度低
缺點:在查詢的時候須要從頭節點開始查找,時間複雜度高。
爲了克服這樣的缺點---雙鏈表,循環鏈表等
1.初始化順序表(參數用引用):
Status InitList_Sq(SqList &L){ //構造一個空的順序表L L.elem=new ElemType[MAXSIZE]; //爲順序表分配空間 if(!L.elem) exit(OVERFLOW); //存儲分配失敗 L.length=0; //空表長度爲0 return OK; }
1.初始化順序表(參數用指針):
Status InitList_Sq(SqList *L){ //構造一個空的順序表L L->elem=new ElemType[MAXSIZE]; //爲順序表分配空間 if(!L->elem) exit(OVERFLOW); //存儲分配失敗 L->length=0; //空表長度爲0 return OK; }
2.取值(根據位置i獲取相應位置數據元素的內容) :
int GetElem(SqList L,int i,ElemType &e) { if (i<1||i>L.length) return 0; //判斷i值是否合理,若不合理,返回0 e=L.elem[i-1]; //第i-1的單元存儲着第i個數據 return 1; }
3.查找(根據指定數據獲取數據所在的位置 ) : 在線性表L中查找值爲e的數據元素
int LocateELem(SqList L,ElemType e) { for (i=0;i< L.length;i++) if (L.elem[i]==e) return i+1; return 0; }
4.插入(插入到第i個結點以前 ) :
Status ListInsert_Sq(SqList &L,int i ,ElemType e){ if(i<1 || i>L.length+1) return ERROR; //i值不合法 if(L.length==MAXSIZE) return ERROR; //當前存儲空間已滿 for(j=L.length-1;j>=i-1;j--) L.elem[j+1]=L.elem[j]; //插入位置及以後的元素後移 L.elem[i-1]=e; //將新元素e放入第i個位置 ++L.length; //表長增1 return OK; }
5.刪除(刪除第i個結點) :
Status ListDelete_Sq(SqList &L,int i){ if((i<1)||(i>L.length)) return ERROR; //i值不合法 for (j=i;j<=L.length-1;j++) L.elem[j-1]=L.elem[j]; //被刪除元素以後的元素前移 --L.length; //表長減1 return OK; }
1. 初始化
【算法步驟】
(1)生成新結點做頭結點,用頭指針L指向頭結點。 (2)頭結點的指針域置空。
Status InitList_L(LinkList &L){ L=new LNode; L->next=NULL; return OK; }
2. 取值(根據位置i獲取相應位置數據元素的內容)
Status GetElem_L(LinkList L,int i,ElemType &e){ p=L->next;j=1; //初始化 while(p&&j<i){ //向後掃描,直到p指向第i個元素或p爲空 p=p->next; ++j; } if(!p || j>i)return ERROR; //第i個元素不存在 e=p->data; //取第i個元素 return OK; }
3. 查找 根據指定數據獲取數據所在的位置
// 在鏈表L中查找值爲e的數據元素,並返回該結點 LNode *LocateELem_L (LinkList L,Elemtype e) { //返回L中值爲e的數據元素的地址,查找失敗返回NULL p=L->next; while(p &&p->data!=e) p=p->next; return p; }
4.插入
【算法步驟】 (一)找到ai-1存儲位置p
(二)生成一個新結點*s
(三)將新結點*s的數據域置爲x
(四)新結點*s的指針域指向結點ai
(五)令結點p的指針域指向新結點s
// 核心代碼 s->next=p->next; p->next= s;
//在L中第i個元素以前插入數據元素e Status ListInsert_L(LinkList &L,int i,ElemType e){ 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=new LNode; //生成新結點s s->data=e; //將結點s的數據域置爲e s->next=p->next; //將結點s插入L中 p->next=s; return OK; }//ListInsert_L
5.刪除
【算法步驟】
(一)找到ai-1存儲位置p
(二)保存要刪除的結點的值
(三)令p->next指向ai的直接後繼結點
(四)釋放結點ai的空間
int ListDelete_L(LinkList &L,int i,ElemType &e){ p=L;j=0; while(p->next &&j<i-1){ //尋找第i個結點,並令p指向其前驅 p=p->next; ++j; } if(!(p->next)||j>i-1) return 0; //刪除位置不合理 q=p->next; //臨時保存被刪結點的地址以備釋放 p->next=q->next; //改變刪除結點前驅結點的指針域 e=q->data; //保存刪除結點的數據域 delete q; //釋放刪除結點的空間 return 1; }
1.雙向鏈表的插入:
// 核心代碼 1. s->prior=p->prior; 2. p->prior->next=s; 3. s->next=p; 4. p->prior=s;
Status ListInsert_DuL(DuLinkList &L,int i,ElemType e){ if(!(p=GetElemP_DuL(L,i))) return ERROR; s=new DuLNode; s->data=e; s->prior=p->prior; p->prior->next=s; s->next=p; p->prior=s; return OK; }
2.雙向鏈表的刪除:
// 核心代碼 1. p->prior->next=p->next; 2. p->next->prior=p->prior;
Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e){ if(!(p=GetElemP_DuL(L,i))) return ERROR; e=p->data; p->prior->next=p->next; p->next->prior=p->prior; delete p; return OK; }
理解單鏈表和雙向鏈表的操做,循環鏈表的操做也相似。這裏不在贅述。
歡迎關注公衆號:coder辰砂 (一個認認真真寫東西的公衆號)