鳥哥說,堅持學習基礎才能有出人頭地的一天。不能只專注於練武功了,內功也得練。
本篇文章是講資料結構的第一篇,跟著書好好再過一篇基礎。
一、線性表
線性表是n個資料特性相同的元素的組成有限序列,是最基本且常用的一種線性結構(線性表,棧,佇列,串和陣列都是線性結構),同時也是其他資料結構的基礎。
對於非空的線性表或者線性結構的特點:
(1)存在唯一的乙個被稱作「第乙個」的資料元素;
(2)存在唯一的乙個被稱作「最後乙個」的資料元素;
(3)除第乙個外,結構中的每個資料元素均只有乙個前驅;
(4)除最後乙個外,結構中的每個資料元素均只有乙個後繼;
二、線性表的兩種實現方式
1.1順序表示(順序表)
特點:邏輯上相鄰的資料元素,物理次序也是相鄰的。
只要確定好了儲存線性表的起始位置,線性表中任一資料元素都可以隨機訪問,所以線性表的順序儲存結構是一種隨機訪問的儲存結構,因為高階語言中的陣列型別也是有隨機訪問的特性,所以通常我們都使用陣列來描述資料結構中的順序儲存結構,用動態分配的一維陣列表示線性表。
1.2 **實現
以最簡單的學生資訊管理為例:
首先先建立兩個資料結構,如下:
#define maxsize 100 //定義學生最大數量
#define ok 1 //正確標誌
#define error 0 //失敗標誌
//學生資訊的資料結構
typedef struct
student;
//順序表資料結構
typedef struct
sqlist;
//定義sqlist型別的變數
sqlistl;
這是乙個十分簡單的例子,這樣我們就可以通過l.elem[i-1]訪問序號為i的學生資訊了。其實這裡我們用到了指標陣列。如果你對指標陣列還不熟悉的話,可以去我寫過的另一篇文章看看:
1.初始化
基本演算法
//初始化順序表基本演算法
status initlist(sqlist &l)
2.取值
基本演算法:
//順序表取值
status get(sqlist &l,int i,elemtype &e)
3.查詢
基本演算法:
//順序表查詢
int find(sqlist l,elemtype e)
5.刪除
//順序表刪除
status listdelete(sqlist &l,int i)
演算法都十分的簡單,眼尖的你可能發現了,為啥有的引數用的是引用,有的不是呢?
這裡我就得講下使用引用作為形參的作用了,主要有三點:
(2)引用型別作為形參,在記憶體中並沒有產生實參的副本,而使用一般變數作為形參,,形參和實參會分別占用不同給的儲存空間,當資料量較大時,使用變數作為形參可能會浪費時間和空間。
(3)雖然使用指標也可以達到引用一樣的效果,但是在被調函式中需要重複使用"*指標變數名"來訪問,很容易產生錯誤並且使程式的閱讀性變差。
此時你會發現,使用順序表作為儲存時,空間是一次性直接開闢的,所以可能會有空間不足或者浪費空間的情況出現,那麼為啥不用乙個就分配乙個空間呢,再使用乙個方式將這些空間串起來不就好了,是時候展現真正的技術了(鍊錶)。
2.1鍊錶
概念:用一組任意的儲存單元儲存線性表的資料元素(這組儲存單元可以是連續的,也可以是不連續的),包括資料域和指標域,資料域存資料,指標域指示其後繼的資訊。
這裡重點講單鏈表,如圖:
2.1**實現
//單鏈表儲存結構
typedef struct lnode
lnode,*linklist;
為了提高程式的可閱讀性,在此對同一結構體指標型別起了兩個名稱,linklist與lnode*,本質上兩者是等價的。通常習慣上用linklist定義單鏈表,強調定義的是某個單鏈表的頭指標,用lnode *定義指向單鏈表中任意結點的指標變數。
例如,定義linklist l,則l為單鏈表的頭指標,若定義lnode *p ,則p為指向單鏈表中某個結點的指標,用*p代表該結點。
1.初始化
基本演算法:
//初始化
status initlist(linklist &l)
2.取值
基本演算法:
//取值
status get(linklist l,int i,elemtype &e)
if(!p||j>i) return error; //不合法
e=p->data; //找到該結點後獲取該結點的資料域
return ok;
}
3.查詢
基本演算法:
//查詢
lnode *find(linklist l,elemtype e)
return p; //這裡有兩種情況,找到的時候返回指標p,如果找不到那麼這個p則為null,因為最後乙個指向的是null
}
4.插入
基本演算法:
//插入
status listinsert(linklist &l,int i,elemtype e)
if(!p||j>i-1) return error;
s=new lnode; //生成乙個新結點
s->data=e; //將結點*s的資料域置為e
s->next=p->next; //先接尾部
p->next=s; //再接頭部
}
5.刪除
基本演算法:
//刪除
status listdelete(linklist &l,int i)
if(!(p->next)||(j>i-1)) return error; //當i>n或i<1時,不符合條件
q=p->next; //臨時儲存被刪除的位址
p->next=q->next; //將前驅結點指向後驅
delete q; //釋放刪除結點的空間
其實單鏈表可以想象成一列人在玩遊戲,每個人都把手搭到後面那個人的肩膀上,每個人身上都有乙個大口袋用來放資料,最後乙個人沒人可以搭就一直懸空著,第乙個帶頭領隊的就不用口袋了,它是乙個頭結點,是用來找到第乙個有口袋的人的,也就是首元結點。
這樣想的話就簡單了,初始化的時候就是用乙個人當頭結點,它沒有口袋,他的手是用來搭到第乙個有口袋的人肩膀的,因為這個人還沒來,所以它的next是null,而取值時,通過引數i,我們就可以從首元結點開始數,數到第i個人,找到他後,就可以拿他口袋裡面的東西,查詢是知道口袋裡面東西是什麼,想找到這個東西的擁有者,也是一樣從首元結點開始找。遍歷下去,插入的話,比如要插入第i個位置,那麼我們就先找到第i-1個人,然後讓新來的手搭到第i個人身上,然後再讓第i-1個人把之前放在第i個人的手挪開,放在新來的人的肩膀上,刪除操作的話,例如刪除第i個人,那麼也是先找到第i-1個人,這裡的重點是,因為鍊錶的查詢只能是從頭開始找的,是不能逆回去的,所以我們需要找個變數把要刪的那個人的位址先存起來,然後把第i-1個的手放到第i+1個人身上,如果我們不找個變數把那個人的位址存起來,這時候我們就沒辦法找到他了,因為我們用乙個變數臨時儲存他的位址,於是我們只需要釋放這個位址的空間就可以了。
這就是單鏈表的基本操作,那麼如何建立單鏈表呢?
主要有著兩種方法(前插法和後插法)
//前插法建立單鏈表
void createlist(linklist &l,int n)
}
//後插法
void createlist(linklist &l,int n)
}
兩種方式的結果是一樣的,區別就是前插法是把新的元素插到最前面,代替了首元結點的位置,就是明擺的插隊,而後插法是插到最後面,有點類似於佇列。而且後插法多了乙個用來指向尾結點的尾指標。
實際上鍊表還有兩種,雙向鍊錶和迴圈鍊錶,迴圈鍊錶用的比較多,就是把頭和尾連起來了,像乙個圈一樣。這裡我就不說明了,因為只要懂了單鏈表,另外兩種理解起來是十分容易的事情。
mysql 線性表 資料結構之線性表
概要 參考 大話資料結構 把常用的基本資料結構梳理一下。線性表定義 線性表 list 零個或多個資料元素的有限序列。若將線性表記為 a 1,cdots,a a i,a cdots,a n 則表中 a 領先於 a i a i 領先於 a 稱 a 是 a i 的直接前驅元素,a 是 a i 的直接後繼元...
資料結構之線性表
從現在開始,我們開始討論如何實現一些常用的資料結構和其中的一些經典演算法.等把資料結構講完了.我可能會繼續討論vc 的程式設計只是以及vs平台下的c c 開發等等.呵呵.我們進入正題吧.我在這裡就只實現線性表的連表結構.當然了,這裡實際上包含了好多知識.我希望大家在引用的時候.一定要領悟裡面的一些變...
資料結構之線性表
線性表是具有相同特性的資料元素的乙個有限序列。該序列中所含元素的個數叫做線性表的長度,用n表示,n 0。當n 0時,表示線性表是乙個空表,即表中不包含任何元素。設序列中第i i表示位序 個元素為ai 1 i n 線性表的一般表示為 a1,a2,ai,ai 1,an include include d...