線性表
線性表的順序存儲結(jié)構(gòu),指的是用一段地址連續(xù)的存儲單元依次存儲線性表的數(shù)據(jù)元素
線性表屬性:
1、存儲空間的起始位置:數(shù)組 data,它的存儲位置就是存儲空間的存儲位置。
2、線性表的最大存儲容量:數(shù)組長度MaxSize(線性表長度)
3、線性表的當(dāng)前長度:length(數(shù)據(jù)長度)
線性表元素獲取O(1):
獲取數(shù)組指定下標(biāo)的值
線性表插入元素O(n):
1、如果插入位置不合理,拋出異常;
2、如果線性表長度大于等于數(shù)組長度,則拋出異常或動態(tài)增加容量
3、從最后一個元素開始向前遍歷到第i個位置,分別將它們都向后移動一個位置;
3、將要插入元素填入位置i處;
4、表長加1
線性表刪除元素O(n):
1、如果刪除位置不合理,拋出異常
2、取出刪除元素
3、從刪除元素位置開始遍歷到最后一個元素位置,分別將它們都向前移動一個位置
4、表長減1
線性表優(yōu)缺點
單鏈表
為了表示每個數(shù)據(jù)元素Ai與其直接后繼數(shù)據(jù)元素Ai+1之間的邏輯關(guān)系,對數(shù)據(jù)元素Ai來說,除了要存儲自身的信息之外,還需蠢豬一個指示其直接后繼的信息(即直接后繼得到存儲位置)。我們把存儲數(shù)據(jù)元素信息的域稱為數(shù)據(jù)域,把存儲直接后繼位置的域稱為指針域。指針域中存儲的信息稱做指針或鏈。這兩部分信息組成數(shù)據(jù)元素Ai的存儲映像,稱為結(jié)點(Node)。
單鏈表查找 O(n)
1、聲明一個結(jié)點p指向鏈表第一個結(jié)點,初始化 j從1開始;
2、. j<i 時,就遍歷鏈表,讓p的指針向后移動,不斷指向下一結(jié)點, j累加1
3、若到鏈表末尾p為空,則說明第i個元素不存在
4、否則查找成功,返回結(jié)點p的數(shù)據(jù)
單鏈表插入O(n)
s->netx = p->next;
p->next = s;
上面兩行代碼的意思就是讓p的后繼結(jié)點變成s的后繼結(jié)點,然后在把結(jié)點s變成p的后繼結(jié)點。并且兩行代碼順序不能改變,否則就會出現(xiàn)鏈表中斷的情況。下面咋們來分析一下。加入代碼變成這樣:
p->next = s;
s->netx = p->next;
意思就是先把S變成p的后繼結(jié)點,這沒有問題,但是接著看下一行代碼,把p的后繼結(jié)點變成s的后繼結(jié)點,因為上一行代碼以及把s變成p的后繼結(jié)點,所以這行代碼的意思就變成了:
p->next = s;
s->netx = s;
s的后繼結(jié)點指向了自己,所以后面的鏈表就斷了。切記兩行代碼順序不能改變。
單鏈表的刪除O(n)
p->next =p->next->next
用q來代替p->next
q=p->next(中間結(jié)點)
p->next = q->next
上面這段代碼的意思其實就是讓p的后繼結(jié)點直接指向p的后繼結(jié)點的后繼結(jié)點,所以q結(jié)點就被孤立了。
總結(jié)
從整個算法來說,我們很容易推導(dǎo)出:它們的時間復(fù)雜度都是 O(n) 。如果在我們
不知道第i個元素的指針位置,單鏈表數(shù)據(jù)結(jié)構(gòu)在插入和刪除操作上,與線性表的順
序存儲結(jié)構(gòu)是沒有太大優(yōu)勢的。但如果,我們希望從第i個位置,插入10個元素,對
于順序存儲結(jié)構(gòu)意味著,每一次插入都需要移動n-i個元素,每次都是 O(n) 。而單
鏈表,我們只需要在第一次時,找到第i個位置的指針,此時為 O(n),接下來只是簡
單地通過賦值移動指針而已,時間復(fù)雜度都是 0(1) 。顯然 ,對于插入或刪除數(shù)據(jù)越頻繁的操作,單鏈表的效率優(yōu)勢就越是明顯。
對比
靜態(tài)鏈表(通過數(shù)組模擬鏈表)
例子:
此時"甲"這里就存有下一元素"乙 的游標(biāo)2 ,"乙"則存有下一元素"丁'的下標(biāo) 3。而"庚"是最后一個有值元素,所以它的 cur 設(shè)置為 0。而最后一個元素的cur 則因"甲'是第一有值元素而存有它的下標(biāo)為1.而第一個元素則因空閑空間的第一個元素下標(biāo)為 7,所以它的 cur 存有7。
總的來說,靜態(tài)鏈表其實是為了給沒有指針的高級語言設(shè)計的一種實現(xiàn)單鏈襲能
力的方法。盡管大家不一定會用得上,但這樣的思考方式是非常巧妙的,應(yīng)該理解其
思想,以備不時之需。
循環(huán)鏈表
把為指針指向頭結(jié)點地址
循環(huán)鏈表合并
p=rearA->next;
rearA->next = rearB->next->next;
rearB->next=p;
free(p);
雙向鏈表
由于這是雙向鏈表,那么對于鏈表中的某一個結(jié)點p,它的后繼的前驅(qū)是誰?當(dāng)然還是它自己。它的前驅(qū)的后繼自然也是它自己,即:
p->next->prior = p = p->prior->next
雙向鏈表插入
s -> prior = p;
s->next = p->next;
p->next->prior = s;
p->next = s;
關(guān)鍵在于它們的順序,由于第2步和第3步都用到了 p->next。如果第4步先執(zhí)行,則會使得 p->next 提前變成了s,使得插入的作完不成。所以我們不妨把上面這張圖在理解的基礎(chǔ)上記憶,順序是先搞定s的前驅(qū)和后繼,再搞定后結(jié)點的前驅(qū),最后解決前結(jié)點的后繼。
雙向鏈表刪除
p->prior->next = p->next;
p->next->prior = p->prior;
free(p)