数据结构线性表之单链表
单链表
线性表的另外一种存 储结构——链式存储(Linked Storage),这样的线性表叫链表(Linked List)。链表不 要求逻辑上相邻的数据元素在物理存储位置上也相邻,因此,在对链表进行插入 和删除时不需要移动数据元素,但同时也失去了顺序表可随机存储的优点。
单链表的定义
链表是用一组任意的存储单元来存储线性表中的数据元素(这组存储单元可 以是连续的,也可以是不连续的)。在存储数据元素时,除 了存储数据元素本身的信息外,还要存储与它相邻的数据元素的存储地址信息。 这两部分信息组成该数据元素的存储映像(Image),称为结点(Node)。把存储据元 素本身信息的域叫结点的数据域(Data Domain),把存储与它相邻的数据元素的存 储地址信息的域叫结点的引用域(Reference Domain)。
如果结点的引用域只存储该结点直接后继结点的存储地址,则该链表叫单链 表(Singly Linked List)。把该引用域叫 next。
把单链表结点看作是一个类,类名为 Node。单链表结点类的实现如下 所示。
public class Node<T> { private T data; //数据域 private Node<T> next; //引用域 //构造器 public Node(T val, Node<T> p) { data = val; next = p; } //构造器 public Node(Node<T> p) { next = p; } //构造器 public Node(T val) { data = val; next = null; } //构造器 public Node() { data = default(T); next = null; } //数据域属性 public T Data { get { return data; } set { data = value; } } //引用域属性 public Node<T> Next { get { return next; } set { next = value; } } }

把单链表看作是一个类,类名叫 LinkList。LinkList类也实现了接口 IListDS。LinkList类有一个字段 head,表示单链表的头引用,所以 head 的类型为 Node。
单链表类 LinkList的实现说明如下所示。
public class LinkList<T> : IListDS<T> { private Node<T> head; //单链表的头引用 //头引用属性 public Node<T> Head { get { return head; } set { head = value; } } //构造器 public LinkList() { head = null; } //求单链表的长度 public int GetLength() { Node<T> p = head; int len = 0; while (p != null) { ++len; p = p.Next; } return len; } //清空单链表 public void Clear() { head = null; } //判断单链表是否为空 public bool IsEmpty() { if (head == null) { return true; } else { return false; } } //在单链表的末尾添加新元素 public void Append(T item) { Node<T> q = new Node<T>(item); Node<T> p = new Node<T>(); if (head == null) { head = q; return; } p = head; while (p.Next != null) { p = p.Next; } p.Next = q; } //在单链表的第i个结点的位置前插入一个值为item的结点 public void Insert(T item, int i) { if (IsEmpty() || i < 1) { Console.WriteLine("List is empty or Position is error!"); return; } if (i == 1) { Node<T> q = new Node<T>(item); q.Next = head; head = q; return; } Node<T> p = head; Node<T> r = new Node<T>(); int j = 1; while (p.Next != null && j < i) { r = p; p = p.Next; ++j; } if (j == i) { Node<T> q = new Node<T>(item); q.Next = p; r.Next = q; } } public void InsertPost(T item, int i) { if (IsEmpty() || i < 1) { Console.WriteLine("List is empty or Position is error!"); return; } if (i == 1) { Node<T> q = new Node<T>(item); q.Next = head.Next; head.Next = q; return; } Node<T> p = head; int j = 1; while (p != null && j < i) { p = p.Next; ++j; } if (j == i) { Node<T> q = new Node<T>(item); q.Next = p.Next; p.Next = q; } } //删除单链表的第i个结点 public T Delete(int i) { if (IsEmpty() || i < 0) { Console.WriteLine("Link is empty or Position is error!"); return default(T); } Node<T> q = new Node<T>(); if (i == 1) { q = head; head = head.Next; return q.Data; } Node<T> p = head; int j = 1; while (p.Next != null && j < i) { ++j; q = p; p = p.Next; } if (j == i) { q.Next = p.Next; return p.Data; } else { Console.WriteLine("The ith node is not exist!"); return default(T); } } //获得单链表的第i个数据元素 public T GetElem(int i) { if (IsEmpty()) { Console.WriteLine("List is empty!"); return default(T); } Node<T> p = new Node<T>(); p = head; int j = 1; while (p.Next != null && j < i) { ++j; p = p.Next; } if (j == i) { return p.Data; } else { Console.WriteLine("The ith node is not exist!"); return default(T); } } //在单链表中查找值为value的结点 public int Locate(T value) { if (IsEmpty()) { Console.WriteLine("List is Empty!"); return -1; } Node<T> p = new Node<T>(); p = head; int i = 1; while (!p.Data.Equals(value) && p.Next != null) { P = p.Next; ++i; } return i; } }
(1)在单链表的头部插入结点建立单链表。 建立单链表从空表开始,每读入一个数据元素就申请一个结点,然后插在链 表的头部。图 2.11 展现了线性表(a1,a2,a3,a4)的链表建立过程。因为是在链表的 头部插入,读入数据的顺序和链表中的逻辑顺序是相反的。

在头部插入结点建立单链表的算法如下:
LinkList<int> CreateLListHead() { int d; LinkList<int> L = new LinkList<int>(); d = Int32.Parse(Console.ReadLine()); while (d != -1) { Node<int> p = new Node<int>(d); p.Next = L.Head; L.Head = p; d = Int32.Parse(Console.ReadLine()); } return L; }
(2)在单链表的尾部插入结点建立单链表。 头部插入结点建立单链表简单,但读入的数据元素的顺序与生成的链表中元 素的顺序是相反的。若希望次序一致,则用尾部插入的方法。因为每次是将新结 点插入到链表的尾部,所以需加入一个引用 R 用来始终指向链表中的尾结点,以 便能够将新结点插入到链表的尾部。图 2.12 展现了在链表的尾部插入结点建立 单链表的过程。

在尾部插入结点建立单链表的算法如下:
LinkList<int> CreateListTail() { Node<int> R = new Node<int>(); int d; LinkList<int> L = new LinkList<int>(); R = L.Head; d = Int32.Parse(Console.ReadLine()); while (d != -1) { Node<int> p = new Node<int>(d); if (L.Head == null) { L.Head = p; } else { R.Next = p; } R = p; d = Int32.Parse(Console.ReadLine()); } if (R != null) { R.Next = null; } return L; }

浙公网安备 33010602011771号