而鍊錶結構正好相反,先來看下結構:
每個元素至少具有二個屬性:data和next。data用來存放資料,而next用來指出它後面的元素是誰(有點「指標」的意思)。
鍊錶中的元素,通常也稱為節點node,下面是泛型版本的node.cs
namespace 線性表
public node(nodep)
public node(t val)
public node()
public t data
set
}public nodenext
set }}
}
鍊錶在儲存上並不要求所有元素按順序儲存,因為用節點的next就能找到下乙個節點,這好象一根「用珠子串成的鍊子」,要找到其中的某一顆珠子,只要從第一
顆節點(通常稱為head節點)開始,不斷根據next指向找到下乙個,直到找到需要的節點為止。
鍊錶中需要有乙個head節點做為開始,這跟順序表有所不同,下面是單鏈表的實現:
using system;
using system.text;
namespace 線性表
set
}public linklist()
/// /// 類索引器
///
///
///
public t this[int index]
}/// /// 返回單鏈表的長度
///
///
public int count()
return len;
}/// /// 清空
///
public void clear()
/// /// 是否為空
///
///
public bool isempty()
/// /// 在最後附加元素
///
///
n = head;
while (n.next != null)
n.next = d;
}//前插
public void insertbefore(t item, int i)
//在最開頭插入
if (i == 0)
noden = head;
noded = new node();
int j = 0;
//找到位置i的前乙個元素d
while (n.next != null && j < i)
if (n.next == null) //說明是在最後節點插入(即追加)
else}}
/// /// 在位置i後插入元素item
///
///
///
public void insertafter(t item, int i)
if (i == 0)
nodep = head;
int j = 0;
while (p != null && j < i)
if (j == i)
else
}/// /// 刪除位置i的元素
///
///
///
public t removeat(int i)
nodeq = new node();
if (i == 0)
nodep = head;
int j = 0;
while (p.next != null && j < i)
if (j == i)
else
}/// /// 獲取指定位置的元素
///
///
///
public t getitemat(int i)
nodep = new node();
p = head;
if (i == 0)
int j = 0;
while (p.next != null && j < i)
if (j == i)
else
}//按元素值查詢索引
public int indexof(t value)
nodep = new node();
p = head;
int i = 0;
while (!p.data.equals(value) && p.next != null)
return i;
}/// /// 元素反轉
///
public void reverse()
this.head = result.head;//將原鍊錶直接掛到"反轉後的鍊錶"上
result = null;//顯式清空原鍊錶的引用,以便讓gc能直接**
}public override string tostring()
return sb.tostring().trimend(',');}}
}
下面是單鏈表插入和刪除的演算法**:
可以看到:鍊錶在元素插入/刪除時,無需對後面的元素進行移動,只需要修改自身以及相鄰節點的next指向即可,所以插入/刪除元素的開銷要比順序表小得多。但是也應該注意到,其它操作比如:查詢元素,反轉倒置鍊錶等,有可能需要遍歷整個鍊錶中的所有元素。
測試**片斷:
console.writeline("-------------------------------------");
console.writeline("單鏈表測試開始...");
linklistlink = new linklist();
link.head = new node("x");
link.insertbefore("w", 0);
link.insertbefore("v", 0);
link.insertbefore("z", link.count());
console.writeline(link.count());//5
console.writeline(link.tostring());//v,w,x,y,z
console.writeline(link[1]);//w
console.writeline(link[0]);//v
console.writeline(link[4]);//z
console.writeline(link.indexof("z"));//4
console.writeline(link.removeat(2));//x
console.writeline(link.tostring());//v,w,y,z
link.insertbefore("x", 2);
console.writeline(link.tostring());//v,w,x,y,z
console.writeline(link.getitemat(2));//x
link.reverse();
console.writeline(link.tostring());//z,y,x,w,v
link.insertafter("1", 0);
link.insertafter("2", 1);
link.insertafter("6", 5);
link.insertafter("8", 7);
link.insertafter("a", 10);//position is error!
console.writeline(link.tostring()); //z,1,2,y,x,w,6,v,8
至於具體在實際應用中應該選用順序表 or 鍊錶,主要是看:對於元素插入/刪除的頻繁程度以及對於記憶體分配的苛刻程度。 如果不要求一開始就分配一組連續的記憶體區域,可以根據元素的增加而自動加大記憶體的使用量,或者插入/刪除的次數很多,那麼建議使用鍊錶,反之用順序表。
最後指出:可以給節點再新增乙個prev元素,用於指出前乙個節點是誰,即同時有next和prev二個指向,這種改進後的鍊錶稱為「雙向鍊錶」,它有助於某些情況下減少遍歷迴圈的次數,本文中的這種僅有乙個next指向的鍊錶,稱為「單鏈表」。
資料結構 單鏈表(C 版)
模擬鍊錶 用兩個陣列模擬動態鍊錶,因為c 中動態記憶體申請太慢,所以用靜態的陣列模擬動態鍊錶,提高演算法效率。基本思路 與動態鍊錶的操作原理和步驟大致相同,只不過是用陣列代替節點,用變數代替指標 模板 head儲存煉表頭,e儲存節點的值 即資料域 ne儲存節點的next指標 即指標域 idx表示當前...
資料結構之單鏈表 C 版
include include using namespace std typedef string elemtype typedef struct lnodelnode,slink void initlist slink l void locateelem slink l void listins...
資料結構筆記 單鏈表
順序表 一.順序儲存結構 與對陣列的操作類似,並無太大新知識點,顧略去。二.鏈式儲存結構 單鏈表的儲存不連續,每個儲存單元既儲存資料元素,又儲存後繼元素的位址。因此,節點結構定義 templatestruct node 為了實現基本操作,建立模板 templateclass llist 單鏈表初始化...