C#数据结构回顾之单链表
来源:互联网 发布:淘大象软件下载 编辑:程序博客网 时间:2024/06/07 13:13
单链表结构解析:
链表是用一组任意的存储单元来存储线性表中的数据元素(这组存储单元可以是连续的,也可以是不连续的)。那么问题来了,怎么表示两个数据元素逻辑上的相邻关系呢?即如何表示数据元素之间的线性关系呢?为此,在存储数据元素时,除了存储数据元素本身的信息外,还要存储与它相邻的数据元素的存储地址信息(所谓的引用域,指针域)。这两部分信息组成该数据元素的存储映像(Image),称为结点(Node),(可以把一个节点理解成为一个数据单元:由两部分组成——data(保存数据)和引用域。)把存储据元素本身信息的域叫结点的数据域(Data Domain),把存储与它相邻的数据元素的存储地址信息的域叫结点的引用域(Reference Domain)。因此,线性表通过每个结点的引用域形成了一根“链条”,这就是“链表”名称的由来。即链表的基本单元就是节点,很多个节点通过引用链接起来就是“链表”。
链表的节点定义
namespace DataStructureLearning.ImplementClass{ //链表节点类 public class LinkNode<T> { #region ----成员变量----- private T data;//数据域,当前结点的值 private LinkNode<T> next;//指针域,指向下一个结点 #endregion #region ----构造方法----- //构造方法 public LinkNode(T val, LinkNode<T> p) { data = val; next = p; } //构造方法只包含引用域的结点 public LinkNode(LinkNode<T> p) { next = p; } //构造方法只包含数据域的结点 public LinkNode(T val) { data = val; next = null; } //构造方法既不包含数据域也不包含引用域的结点 public LinkNode() { data = default(T); next = null; } #endregion #region ----公有属性----- //数据域属性 public T Data { get { return data; } set { data = value; } } //引用域属性 public LinkNode<T> Next { get { return next; } set { next = value; } } #endregion }}
单链表类的实体类:
既然单链表就是由很多节点通过引用域连接起来形成链表的,那么这个实体类的数据成员自然而然包含节点类的变量和一些常用的操作。常用的单链表由头引用H唯一确定。头引用指向单链表的第一个结点,也就是把单链表第一个结点的地址放在H中,所以,H是一个Node类型的变量。头引用为null表示一个空表。 头结点的加入完全是为了操作的方便(遍历的时候,不带头结点的单链表是把头引用head赋给一个结点变量,即p = head,p为结点变量;而带头结点的单链表是把head的引用域赋给一个结点变量,即p = head.Next,p为结点变量),它的数据域无定义,引用域存放的是第一个结点的地址,空表时该引用域为空。以下几个常用的操作:
LinkNode p = head;
LinkNode node = new LinkNode(item);
- 移动到下一个节点:p=p.Next
- 改变节点的指向: node.Next = p;
using System;using System.Collections.Generic;using System.Linq;using System.Text;using DataStructureLearning.Interface;namespace DataStructureLearning.ImplementClass{ public class SingleLinkList<T> : IListDataStructure<T> { #region ------成员变量----- private LinkNode<T> head;//表示单链表的头节点的引用,不保存数据只保存引用域,head为空的时候说明是空链表,头引用指向单链表的第一个结点,也就是把单链表第一个结点的地址放在H中,所以,H是一个Node类型的变量。头引用为null表示一个空表。head的类型为Node<T>假如第一个节点的,head永远都是保存单链表第一个节点的引用 #endregion #region ------构造方法----- //构造器 public SingleLinkList() { head = null; } #endregion #region ------公有属性----- //头引用属性 public LinkNode<T> HEAD { get { return head; } set { head = value; } } #endregion #region ------成员方法----- // public int GetLength() { // 设置指针指向头结点 LinkNode<T> p = head; int len = 0; // 当前指针指向的地址不是为null时表示存在该结点 while (p != null) { len++; p = p.Next; } return len; } //清空单链表 // 此处只是将头结点的引用域设置为null的逻辑清空,在内存中数据依旧存在 // 但是.NET的垃圾回收器会为我们回收这部分垃圾 public void Clear() { head = null;//头指针只为null之后 GC会自动回收 } //判断单链表是否为空 public bool IsEmpty() { // 根据头结点的引用域是否为null判断是否为空 if (head == null) { return true; } else { return false; } } //在单链表的末尾添加新元素 //单链表的附加操作也需要从单链表的头引用开始遍历单链表,直到单链表的末尾,然后在单链表的末端添加一个新结点。 public void Append(T item) { LinkNode<T> q = new LinkNode<T>(item);//待添加的节点引用域 LinkNode<T> p = new LinkNode<T>();//最后一个节点的引用域 // 判断此时是否为空表,是则直接修改头结点的引用域 if (head == null) { head = q; return; } // 不是则遍历结点,找到最后最后一个结点,则head为第一个节点,head.Next为第二个节点的引用 else { 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) { LinkNode<T> q = new LinkNode<T>(item); q.Next = head;//链表的新增节点的引用域为空即该链表是最后一个节点 head = q;//在第一个节点的前面插入q所以第一个节点变为q,而head引用需要修改为q,因为head //永远都是指向第一个节点的引用,头结点指向新增节点的引用域即该节点也是该链表的第一个节点 return; } // 遍历直到当前结点的位置为i // 如果插入位置超过单链表长度,则插入失败 else { LinkNode<T> p = head;//初始化为头结点,遍历的起点节点,p保存第i个节点的引用 LinkNode<T> pre = new LinkNode<T>();//p的前一个节点 int j = 1; // 遍历直到当前结点的位置为i // 如果插入位置超过单链表长度,则插入失败 while (p.Next != null && j < i) { pre = p; p = p.Next; j++; } if (j == i) { LinkNode<T> node = new LinkNode<T>(item); node.Next = p; pre.Next = node; } } } //在单链表的第i个结点的位置前插入一个值为item的结点 public void InsertPost(T item, int i) { if (IsEmpty() || i < 1) { Console.WriteLine("List is empty or Position is error!"); return; } if (i == 1) { LinkNode<T> q = new LinkNode<T>(item); q.Next = head.Next; head.Next = q; return; } LinkNode<T> p = head; int j = 1; while (p.Next != null && j < i) { p = p.Next; j++; } if (j == i) { LinkNode<T> q = new LinkNode<T>(item); q.Next = p.Next; p.Next = q; } else { Console.WriteLine("Position is error!"); } return; } //删除单链表的第i个结点 public T Delete(int i) { if (IsEmpty()|| i < 0) { Console.WriteLine("Link is empty or Position is error!"); return default(T); } LinkNode<T> q = new LinkNode<T>(); if (i == 1) { q = head; head = head.Next;//head为第一个节点的引用,head.Next则是第二个节点的引用 return q.Data; } //遍历找到要删除的节点p LinkNode<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); } LinkNode<T> p = new LinkNode<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; } LinkNode<T> p = new LinkNode<T>(); p = head; int i = 1; while (!p.Data.Equals(value)&& p.Next != null) { p = p.Next; ++i; } return i; } // 打印单链表所有结点 public void DisplayItems() { // 判断是否为空表 if (IsEmpty()) { Console.WriteLine("单链表表中不存在数据元素,无法执行打印操作,操作失败!"); } // 执行打印操作 else { LinkNode<T> p = new LinkNode<T>(); p = head; while (p.Next != null) { Console.Write(p.Data + "\t"); p = p.Next; } // 打印最后一个结点 Console.Write(p.Data + "\t"); Console.WriteLine(); } } //反转 public void ReversLinkList(SingleLinkList<int> H) { LinkNode<int> p = H.head; LinkNode<int> q = new LinkNode<int>(); H.head = null; while (p != null) { q = p; p = p.Next; q.Next = H.head; H.head = q; } } #endregion } }
简单测试:
#region -----单链表的操作------ SingleLinkList<int> link = new SingleLinkList<int>(); link.Append(1); link.Append(2); Console.WriteLine("初始化链表:"); link.DisplayItems(); Console.WriteLine("在链表的第2个节点前插入4初始化链表:"); link.Insert(4, 1); link.DisplayItems(); Console.WriteLine("在链表的第1个节点后插入6初始化链表:"); link.InsertPost(6, 2); link.DisplayItems(); Console.WriteLine("取链表第2个节点的元素"); Console.WriteLine(link.GetElem(2)); Console.WriteLine("删除链表的第2个节点后的链表:"); //link.Delete(2); link.DisplayItems(); Console.WriteLine("反转后的单链表:"); link.ReversLinkList(link); link.DisplayItems(); #endregion
- C#数据结构回顾之单链表
- C#数据结构回顾之顺序表
- C#数据结构回顾之顺序栈
- C#数据结构回顾之链栈
- C#数据结构回顾之循环队列
- 【课堂回顾】数据结构之单链表
- 回顾数据结构(1):单链表
- 数据结构回顾:树(之1)
- 数据结构回顾
- c#回顾之泛型编程
- 回顾c#
- C#回顾
- C#回顾
- C#回顾
- C#回顾
- 回顾数据结构之栈的应用-表达式求值
- C#数据结构之优先队列
- 数据结构和算法之C#
- 监控 Linux 性能的 18 个命令行工具
- 哈夫曼编码
- 【学习笔记】宏定义基础
- iOS开发-使用UIImagePickerController遇到的问题
- 进程的三种状态详解
- C#数据结构回顾之单链表
- CAShapeLayer和CAGradientLayer:圆形进度条和动画
- i2c_check_functionality函数的实现
- C++ string 类 学习笔记
- 1037. 在霍格沃茨找零钱(20)
- 和差值最小的数组划分问题
- Interleaving String
- 数据库-删除表中重复记录实现方法分析
- Count Primes