線性結(jié)構(gòu)的基本特點(diǎn)是除第一個(gè)元素?zé)o直接前驅(qū),最后一個(gè)元素?zé)o直接后繼之外,其他每個(gè)元素都有一個(gè)前驅(qū)和后繼。
2.1線性表(Linear List)的定義和特點(diǎn):
定義:由n(n>=0)個(gè)數(shù)據(jù)特性相同的元素構(gòu)成的有限序列稱為線性表,n=0時(shí)稱為空表痴奏。
? ? ? ? 實(shí)例:
特點(diǎn):
稱為線性表的首節(jié)點(diǎn),稱為線性表的尾節(jié)點(diǎn)
都是的前驅(qū)厌秒,其中是的直接前驅(qū)读拆;
都是的后繼简僧,其中是的直接后繼建椰;
2.2線性表的邏輯結(jié)構(gòu)
2.3線性表的抽象數(shù)據(jù)類型定義
ADT List{
? ? ? ? 數(shù)據(jù)對(duì)象:D = { |? }
? ? ? ? 數(shù)據(jù)關(guān)系:R = {}
? ? ? ? 基本操作:
? ? ? ? ? ? ? ? 操作名1:
? ? ? ? ? ? ? ? ? ? ? ? 初始條件
? ? ? ? ? ? ? ? ? ? ? ? 操作結(jié)果1
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .
? ??????????????????????????????.
? ??????????????????????????????.
}ADT List
2.4線性表的順序存儲(chǔ)和實(shí)現(xiàn)
順序存儲(chǔ):把線性表的節(jié)點(diǎn)按邏輯順序依次存放在一組地址連續(xù)的存儲(chǔ)單元里岛马,用這種方法存儲(chǔ)的線性表簡(jiǎn)稱順序表棉姐。
特點(diǎn):
? ? ? ? 線性表的邏輯順序與物理順序一致
? ? ? ? 數(shù)據(jù)元素之間的關(guān)系是以元素在計(jì)算機(jī)內(nèi)“物理位置相鄰”來(lái)體現(xiàn)。
順序表的基本操作:
? ? ? ? C語(yǔ)言定義結(jié)構(gòu)體
? ? ? ? 1)順序線性表初始化
? ? ? ? 2)順序線性表的插入
js代碼實(shí)現(xiàn)順序線性表的插入:
? ? ? ? 3)順序線性表的刪除
js代碼實(shí)現(xiàn)順序線性表的刪除
2.5線性表的鏈?zhǔn)酱鎯?chǔ)
鏈?zhǔn)酱鎯?chǔ):用一組任意的存儲(chǔ)單元存儲(chǔ)線性表中的數(shù)據(jù)元素伞矩,用這種方法存儲(chǔ)的線性表簡(jiǎn)稱線性鏈表。
????????存儲(chǔ)鏈表中節(jié)點(diǎn)的一組任意存儲(chǔ)單元可以是連續(xù)的夏志,也可以是不連續(xù)的乃坤,甚至零散分布至內(nèi)存的任意位置上
????????鏈表中節(jié)點(diǎn)的邏輯順序和物理順序不一定相同。
為了正確表示結(jié)點(diǎn)間的邏輯關(guān)系沟蔑,在存儲(chǔ)每個(gè)結(jié)點(diǎn)值的同時(shí)湿诊,還必須存儲(chǔ)指示其直接后繼節(jié)點(diǎn)的地址,C中稱為指針瘦材,節(jié)點(diǎn)值(數(shù)據(jù)域)和地址(指針)兩者組成鏈表中的結(jié)點(diǎn)結(jié)構(gòu)厅须。
????????鏈表通過(guò)每個(gè)結(jié)點(diǎn)的地址將線性表的n個(gè)結(jié)點(diǎn)按其邏輯順序連接在一起。
????????每一個(gè)結(jié)點(diǎn)只包含一個(gè)地址域的鏈表稱為單鏈表食棕。
????????為操作方便朗和,總是在鏈表的第一個(gè)結(jié)點(diǎn)之前附設(shè)一個(gè)頭節(jié)點(diǎn)head指向第一個(gè)結(jié)點(diǎn),頭節(jié)點(diǎn)的數(shù)據(jù)域可以不存儲(chǔ)任何信息(或鏈表長(zhǎng)度信息)簿晓。
下圖可以看出鏈表中節(jié)點(diǎn)的邏輯順序和物理順序不一定相同眶拉。
結(jié)點(diǎn)的描述與實(shí)現(xiàn)
C語(yǔ)言中,用帶指針的結(jié)構(gòu)體來(lái)描述
typedef struct Lnode{
????ElemType data憔儿;//數(shù)據(jù)域忆植,保存結(jié)點(diǎn)的值
????struct Lnode *next;//指針域
}LNode;? //結(jié)點(diǎn)的類型
結(jié)點(diǎn)的實(shí)現(xiàn):
結(jié)點(diǎn)是通過(guò)動(dòng)態(tài)分配指針和釋放來(lái)實(shí)現(xiàn),即需要時(shí)分配皿曲,不需要時(shí)釋放唱逢。是現(xiàn)實(shí)是分別使用C語(yǔ)言提供的標(biāo)準(zhǔn)函數(shù):malloc(),realloc(),sizeof(),free()。
動(dòng)態(tài)分配:
p = (LNode*)malloc(sizeof(LNode));
函數(shù)malloc分配了一個(gè)類型為L(zhǎng)Node的結(jié)點(diǎn)變量的空間屋休,并將其首地址放如指針變量p中坞古。
動(dòng)態(tài)釋放:free(p)
系統(tǒng)回收由指針變量p所指向的內(nèi)存區(qū),p必須是最近一次調(diào)用malloc函數(shù)時(shí)的返回值劫樟。
最常見(jiàn)的基本操作及其示意圖
2.6單線性鏈表的基本操作
單項(xiàng)現(xiàn)象鏈表的基本操作
<script>
????//設(shè)計(jì)一個(gè)基于對(duì)象的鏈表
????//創(chuàng)建鏈表Node類
????function?Node(element){
????????this.element?=?element;
????????this.next?=?null;
????}
????//創(chuàng)建鏈表/增刪改查
????function?LinkedList(){
????????this.head?=?new?Node('head');//創(chuàng)建頭結(jié)點(diǎn)
????????this.find?=?find;?//查找結(jié)點(diǎn)
????????this.insert?=?insert;//插入結(jié)點(diǎn)
????????this.findPrev?=?findPrev;//找到某結(jié)點(diǎn)的前一結(jié)點(diǎn)
????????this.remove?=?remove;//刪除結(jié)點(diǎn)
????????this.display?=?display;//顯示鏈表元素
????????//查找對(duì)應(yīng)item的結(jié)點(diǎn)并返回
????????function?find(item){
????????????var?currentNode?=?this.head;//從頭節(jié)點(diǎn)開(kāi)始搜索
????????????//循環(huán)遍歷痪枫,直至找到item結(jié)束
????????????while(currentNode.element!=item){
????????????????currentNode?=?currentNode.next;
????????????}
????????????//返回item的結(jié)點(diǎn)
????????????return?currentNode;
????????}
????????//在item后插入新元素
????????function?insert(newElement,item){
????????????var?newNode?=?new?Node(newElement);//定義新元素結(jié)點(diǎn)
????????????var?current?=?this.find(item);//從鏈表中找到item結(jié)點(diǎn)
????????????newNode.next?=?current.currentNode;//將item元素的結(jié)點(diǎn)后繼賦值給新元素結(jié)點(diǎn)的后繼
????????????current.next?=?newNode;//item元素的后繼插入新元素
????????}
????????//顯示鏈表
????????function?display(){
????????????var?currentNode?=?this.head;
????????????while(!(currentNode.next==null)){
????????????????console.log(currentNode.next.element);
????????????????currentNode?=?currentNode.next;
????????????}
????????}
????????//刪除鏈表的item結(jié)點(diǎn)元素
????????//1.找到item結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)
????????function?findPrev(item){
????????????var?currentNode?=?this.head;//定義待刪除結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)
????????????/*
????????????算法分析:
????????????循環(huán)遍歷currentNode的下一個(gè)結(jié)點(diǎn),如果找到對(duì)應(yīng)等于item的currentNode.next.element,
????????????while循環(huán)結(jié)束返回當(dāng)前的currentNode叠艳,即待刪除元素的前一個(gè)結(jié)點(diǎn)
????????????*/
????????????while(!(currentNode.next==null)?&&?currentNode.next.element!=item){
???????????????currentNode?=?currentNode.next;
????????????}
????????????return?currentNode;
????????}
????????//2.刪除item階段元素
????????function?remove(item){
????????????var?prevNode?=?this.findPrev(item);//找到待刪除結(jié)點(diǎn)的前一結(jié)點(diǎn)
????????????if(!(prevNode.next==null)){
????????????????prevNode.next?=?prevNode.next.next;
????????????}
????????}
????}
????//測(cè)試程序
????var?cities?=?new?LinkedList();
????cities.insert('北京','head');
????cities.insert('上海','北京');
????cities.insert('廣州','上海');
????cities.insert('天津','廣州');
????cities.display();//北京?上海?廣州?天津
????cities.remove('北京');
????cities.display();//上海?廣州?天津
????console.log(cities.find('上海').next)//Node?{element:?"廣州",?next:?Node}
????console.log(cities.find('天津').next);//undefined
</script>
雙向鏈表的基本操作
<script>
????//設(shè)計(jì)一個(gè)基于對(duì)象的雙向鏈表
????//創(chuàng)建鏈表Node類
????function?Node(element){
????????//data數(shù)據(jù)
????????this.element?=?element;
????????//后繼地址
????????this.next?=?null;
????????//前驅(qū)地址
????????this.previous?=?null;
????}
????//創(chuàng)建鏈表/增刪改查
????function?LinkedList(){
????????this.head?=?new?Node('head');//創(chuàng)建頭結(jié)點(diǎn)
????????this.find?=?find;?//查找當(dāng)前結(jié)點(diǎn)
????????this.insert?=?insert;//插入結(jié)點(diǎn)
????????this.findPrevious?=?findPrevious;//找到某結(jié)點(diǎn)的前一結(jié)點(diǎn)
????????this.remove?=?remove;//刪除結(jié)點(diǎn)
????????this.display?=?display;//顯示鏈表元素
????????this.findLast?=?findLast;//查找鏈表最后一個(gè)元素
????????this.dispReverse?=?dispReverse;//反向顯示
????????//查找對(duì)應(yīng)item的結(jié)點(diǎn)并返回
????????function?find(item){
????????????var?currentNode?=?this.head;//從頭節(jié)點(diǎn)開(kāi)始搜索
????????????//循環(huán)遍歷奶陈,直至找到item結(jié)束
????????????while(currentNode.element!=item){
????????????????currentNode?=?currentNode.next;
????????????}
????????????//返回item的結(jié)點(diǎn)
????????????return?currentNode;
????????}
????????//在item后插入新元素
????????function?insert(newElement,item){
????????????var?newNode?=?new?Node(newElement);//定義新元素結(jié)點(diǎn)
????????????var?current?=?this.find(item);//從鏈表中找到item結(jié)點(diǎn)
????????????newNode.next?=?current.currentNode;//將item元素的結(jié)點(diǎn)后繼賦值給新元素結(jié)點(diǎn)的后繼
????????????newNode.previous?=?current;//將item元素賦值給新元素結(jié)點(diǎn)的前驅(qū)
????????????current.next?=?newNode;//item元素的后繼插入新元素
????????}
????????//顯示鏈表
????????function?display(){
????????????var?currentNode?=?this.head;
????????????while(!(currentNode.next==null)){
????????????????console.log(currentNode.next.element);
????????????????currentNode?=?currentNode.next;
????????????}
????????}
????????//刪除鏈表的item結(jié)點(diǎn)元素
????????//1.找到item結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)
????????function?findPrevious(item){
????????????var?currentNode?=?this.head;//定義待刪除結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)
????????????/*
????????????算法分析:
????????????循環(huán)遍歷currentNode的下一個(gè)結(jié)點(diǎn),如果找到對(duì)應(yīng)等于item的currentNode.next.element,
????????????while循環(huán)結(jié)束返回當(dāng)前的currentNode附较,即待刪除元素的前一個(gè)結(jié)點(diǎn)
????????????*/
????????????while(!(currentNode.next==null)?&&?currentNode.next.element!=item){
???????????????currentNode?=?currentNode.next;
????????????}
????????????return?currentNode;
????????}
????????//2.刪除item階段元素
????????function?remove(item){
????????????var?currentNode?=?this.find(item);//找到當(dāng)前待刪除結(jié)點(diǎn)
????????????if(!(prevNode.next==null)){
????????????????currentNode.previous.next?=?currentNode.next;//前一個(gè)元素結(jié)點(diǎn)的的后繼指向當(dāng)前元素的下一個(gè)元素結(jié)點(diǎn)
????????????????currentNode.next.previous?=?currentNode.previous//后一個(gè)元素結(jié)點(diǎn)的前驅(qū)指向當(dāng)前元素的前一個(gè)元素結(jié)點(diǎn)
????????????????currentNode.next?=?null;//當(dāng)前結(jié)點(diǎn)后繼為空
????????????????currentNode.previous?=?null;//當(dāng)前結(jié)點(diǎn)前驅(qū)為空
????????????}
????????}
????????//雙向鏈表查找最后一個(gè)結(jié)點(diǎn)
????????function?findLast(){
????????????var?currentNode?=?this.head;//從頭節(jié)點(diǎn)開(kāi)始搜索
????????????//循環(huán)遍歷,直到地址為空
????????????while(!(currentNode.next==null)){
????????????????currentNode?=?currentNode.next;
????????????}
????????????//最后的結(jié)點(diǎn)
????????????return?currentNode;
????????}
????????//反序顯示雙向鏈表中的元素
????????function?dispReverse(){
????????????var?currentNode?=?this.findLast();
????????????while(!(currentNode.previous==null)){
????????????????console.log(currentNode.element);
????????????????currentNode?=?currentNode.previous;
????????????}
????????}
????}
????//測(cè)試程序
????var?cities?=?new?LinkedList();
????cities.insert('北京','head');
????cities.insert('上海','北京');
????cities.insert('廣州','上海');
????cities.insert('天津','廣州');
????cities.display();//北京?上海?廣州?天津
????cities.dispReverse();//天津?廣州?上海?北京
????console.log(cities.find('上海').next)//Node?{element:?"廣州",?next:?Node}
????console.log(cities.find('天津').next);//undefined
</script>
2.7循環(huán)鏈表
循環(huán)鏈表是一種頭尾相接的鏈表吃粒,其特點(diǎn)是最后一個(gè)結(jié)點(diǎn)的指針指向鏈表的頭節(jié)點(diǎn),整個(gè)鏈表的指針域連接成一個(gè)環(huán)拒课。
從循環(huán)鏈表的任意一個(gè)結(jié)點(diǎn)出發(fā),都可以找到鏈表中的其他結(jié)點(diǎn)。