[参考文献: 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;
}
}
}
}