[參考文獻: 1.嚴蔚敏.資料結構(C語言版) ; 2.陳廣.資料結構(C#語言描述) ;3.Michael McMillan.Data Structures and Algorithms Using C#]
1.線性表的鏈式儲存結構:
用一組任意的儲存單元(不要求地址連續)來儲存線性表的元素,每個元素對應一組儲存單元(稱為結點),每個結點包括兩個域: 儲存資料元素資訊的資料域和儲存直
接後繼所在位置的指標域.
. N個結點通過指標域組成的表, 稱為線性鏈表(單鏈表).
. 線性鏈表最後一個結點的指標域為"空” (NULL 或 ^);
. 用一個頭指標指示鏈表中第一個結點的儲存位置;
. 鏈表L = (a1 ,a2 , ……an ) 邏輯表示為 :
L -> a1 -> a2-> -> an^
空表時: L = NULL .
2.帶頭結點的鏈表:
線上性鏈表的第一個元素結點之前附設一個結點(稱頭結點), 它的資料域不儲存任何資訊,其指標域儲存第一個元素結點的儲存位置. 頭指標L指向該頭結點.
空表時: L->next = NULL
帶頭結點鏈表的引入是為了使演算法判空和處理一致. (空表包含頭結點)
3.線性錶鏈式儲存結構的特點:
(1) 邏輯上相鄰的元素, 其物理位置不一定相鄰; 元素之間的鄰接關係由指標域指示.
(2) 鏈表是非隨機存取儲存結構; 對鏈表的存取必須從頭指標開始; 鏈表結點只能順序訪問,隨機訪問效能不佳.
(3) 鏈表是一種動態儲存裝置結構; 鏈表的結點可調用new() 申請和dispose()釋放[當然C#中是通過記憶體回收行程管理記憶體的].
(4) 插入刪除運算非常方便; 只需修改相應指標值.
以下是用C#實現的一個單鏈表類:
using System;
namespace LinkedList
{
public class LinkedList
{
//成員
private int count; //記錄元素個數, 表長, 初始值為0
private Node head;
//屬性
public int Count //單鏈表中的元素個數
{
get { return count; }
}
//索引器
public object this[int index]
{
get { return Get(index).item; }
set { Get(index).item = value; }
}
//方法
//構造器
public LinkedList() //構造帶有頭結點的單鏈表
{
head = new Node("頭結點");
}
private Node Get(int index) //尋找指定索引的元素:[1 <= index <= 表長 ]
{
int j = 1;
Node p = this.head.next; //初始化,p指向第一個結點,j為計數器
while ((p != null) && (j < index)) //尋找第index個結點.[出迴圈的條件是:(1)p==null: 空表 OR index>表長 ; AND (2)j == index:已定位在第index個結點 ]
{
p = p.next;
++j;
}
if ((p == null) || (j > index))
{
//Console.WriteLine("空表或i小於1或者大於表長");
//Console.ReadLine();
//System.Environment.Exit(0);
throw new ArgumentOutOfRangeException("空表或i小於1或者大於表長");
}
else //***[條件: p != null AND j==index ]
{
return p;
}
//if ((p != null) && (j == index)) //還可以這樣寫!
//{
// return p;
//}
//else
//{
// throw new ArgumentOutOfRangeException("空表或i小於1或者大於表長");
//}
}
public void Add(object value) //在鏈表的結尾添加元素
{
Node p = new Node(value);
if (this.head.next == null) //如果是空表,直接在頭結點後插入
{
head.next = p;
}
else
{
Get(count).next = p;
}
count++;
}
public void Insert(int index, object value) //在指定索引處之前插入元素: [1 <= index <= 表長+1 ]
{
int j = 0;
Node p = this.head; //初始化,p指向頭結點,j為計數器
while ((p != null) && (j < (index - 1))) //尋找第index - 1個結點.[出迴圈的條件是:(1)p==null: index>表長+1 ; AND (2)j == index-1:已定位在index的前一個結點 ]
{
p = p.next;
++j;
}
if ((p == null) || (j > (index - 1))) //index小於1或者大於表長加1 [ERROR返回條件:(1)p==null: index>表長+1 ; OR (2)j>(index-1): index位置 < 1 ]
{
throw new ArgumentOutOfRangeException("i小於1或者大於表長加1");
}
else //***[條件: p != null AND j==index-1 ]
{
Node s = new Node(value); //產生新結點
s.next = p.next; //插入
p.next = s;
count++; //表長+1
}
}
public void Delete(int index) //刪除指定索引元素 : [1 <= index <= 表長 ]
{
int j = 0;
Node p = this.head; //初始化,p指向頭結點,j為計數器
while ((p.next != null) && (j < (index - 1))) //尋找第index - 1個結點.[出迴圈的條件是:(1)p.next==null: index>表長 ;(2)j == index-1:已定位在index的前一個結點 ]
{
p = p.next;
++j;
}
if ((p.next == null) || (j > (index - 1))) //index小於1或者大於表長 [ERROR返回條件:(1)p.next==null: index>表長 ; OR (2)j>(index-1): index位置 < 1 ]
{
throw new ArgumentOutOfRangeException("i小於1或者大於表長");
}
else //***[條件: p.next != null AND j==index-1 ]
{
p.next = p.next.next; //刪除
count--; //表長-1
}
}
public override string ToString() //列印整個鏈表
{
string s = string.Empty;
for (Node p = head.next ; p != null; p = p.next)
{
s += p.item.ToString() + " ";
}
return s;
}
private class Node //結點類
{
public object item; //資料域
public Node next; //指標域
public Node()
{
item = null;
next = null;
}
public Node(object value)
{
item = value;
next = null;
}
}
}
}