C# 数据结构 - 单链表 双链表 环形链表
链表特点(单链表 双链表)
优点:插入和删除非常快。因为单链表只需要修改Next指向的节点,双链表只需要指向Next和Prev的节点就可以完成插入和删除操作。
缺点:当需要查找某一个节点的时候就需要一个节点一个节点去访问,这样所花的时候就比较多了。(顺序表可以弥补这缺点,但插入和删除就非常耗性能)
单链表
单链表的构成:必须要有一个链表头(head),每个节点里面有一个Next用于指向下一个节点(类似于指针)。最后一个节点的Next为null来标识链表的尾。
如下图
代码实现
/* ------------ 单链表 ------------- */
//链表头
SingleLink head = new SingleLink();
SingleLink node;
//添加节点
node = new SingleLink(, "刘德华");
SingleLink.Add(ref head, node);
node = new SingleLink(, "张学友");
SingleLink.Add(ref head, node);
node = new SingleLink(, "郭富城");
SingleLink.Add(ref head, node);
node = new SingleLink(, "黎明");
SingleLink.Add(ref head, node);
//删除节点
SingleLink.Remove(ref head, );
//遍历所有节点
SingleLink cursor = head;
while (cursor.Next != null)
{
Console.WriteLine(cursor.Next.ToString());
cursor = cursor.Next;
}
/// <summary>
/// 单链表
/// </summary>
public class SingleLink
{
public int No { get; set; }
public string Name { get; set; }
//指向下一个节点(有点像指针)
public SingleLink Next { get; set; }
public SingleLink() { }
public SingleLink(int no, string name)
{
this.No = no;
this.Name = name;
}
/// <summary>
/// 添加
/// </summary>
/// <param name="head">链表头</param>
/// <param name="addNode">添加节点</param>
public static void Add(ref SingleLink head, SingleLink addNode)
{
SingleLink cursor = head;
while (cursor.Next != null)
{
cursor = cursor.Next;
}
cursor.Next = addNode;
}
/// <summary>
/// 删除
/// </summary>
/// <param name="head">链表头</param>
/// <param name="no">删除编号</param>
public static void Remove(ref SingleLink head, int no)
{
SingleLink cursor = head;
while (cursor.Next !=null)
{
if (cursor.Next.No == no)
{
cursor.Next = cursor.Next.Next;
return;
}
cursor = cursor.Next;
}
}
/// <summary>
/// 输入信息(重写ToString方法)
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "No---> " + No + " Name---> " + Name;
}
}
代码分析图
双链表
双链表的构成:双链表跟单链表差不多,也是必须要有一个链表头(head),每个节点里面有一个Next,最后一个节点的Next为null来标识链表的尾。只不过双链表在每个节点上面添加一个Prev,来标识当前节点的上一个节点。
如图:
代码实现
/* ------------ 双链表 ------------- */
//链表头
DoubleLink head = new DoubleLink();
DoubleLink node;
//添加节点
node = new DoubleLink(,"刘德华");
DoubleLink.Add(ref head, node);
node = new DoubleLink(, "张学友");
DoubleLink.Add(ref head, node);
node = new DoubleLink(, "郭富城");
DoubleLink.Add(ref head, node);
node = new DoubleLink(, "黎明");
DoubleLink.Add(ref head, node);
//删除节点
DoubleLink.Remove(ref head,);
//遍历所有节点
DoubleLink cursor = head;
while (cursor.Next != null)
{
Console.WriteLine(cursor.Next.ToString());
cursor = cursor.Next;
}
/// <summary>
/// 双链表
/// </summary>
public class DoubleLink
{
public int No { get; set; }
public string Name { get; set; }
//下个节点
public DoubleLink Prev { get; set; }
//上个节点
public DoubleLink Next { get; set; }
public DoubleLink() { }
public DoubleLink(int no, string name)
{
this.No = no;
this.Name = name;
}
/// <summary>
/// 添加
/// </summary>
/// <param name="head">链表头</param>
/// <param name="addNode"></param>
public static void Add(ref DoubleLink head, DoubleLink addNode)
{
DoubleLink cursor = head;
while (cursor.Next != null)
{
cursor = cursor.Next;
}
cursor.Next = addNode;
cursor.Next.Prev = cursor;
}
/// <summary>
/// 删除
/// </summary>
/// <param name="head">链表头</param>
/// <param name="no">删除编号</param>
public static void Remove(ref DoubleLink head, int no)
{
DoubleLink cursor = head.Next;
while (cursor != null)
{
if (cursor.No == no)
{
//防止是删除最后一个
if (cursor.Next != null)
{
cursor.Next.Prev = cursor.Prev;
}
cursor.Prev.Next = cursor.Next;
return;
}
cursor = cursor.Next;
}
}
/// <summary>
/// 输入信息(重写ToString方法)
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "No---> " + No + " Name---> " + Name;
}
}
代码分析图
环形链表
环形链表是在单链表基础之上把尾指向头就构成了一个环形的链表了。也就是单链表最后一个节点的Next指Head就可以了。
如图:
代码实现
//环形链表
LoopLink head = new LoopLink();
LoopLink node; //添加节点
node = new LoopLink(, "刘德华");
LoopLink.Add(ref head, node); node = new LoopLink(, "张学友");
LoopLink.Add(ref head, node); node = new LoopLink(, "郭富城");
LoopLink.Add(ref head, node); node = new LoopLink(, "黎明");
LoopLink.Add(ref head, node); LoopLink.Remove(ref head, ); //遍历所有节点(遍历需要拿到它的头或者尾来标识链表的结束位置,我是拿到头来遍历的)
LoopLink cursor = head;
LoopLink first = head;
//首先输出头的信息
Console.WriteLine(head);
//遍历所有节点,如果遍历到头节点就退出循环,链表打印完成
while (!Object.ReferenceEquals(cursor.Next, first))
{
Console.WriteLine(cursor.Next.ToString());
cursor = cursor.Next;
} /// <summary>
/// 环形链表
/// </summary>
class LoopLink
{ public int No { get; set; } public string Name { get; set; } public LoopLink Next { get; set; } public LoopLink() { } public LoopLink(int no, string name)
{
this.No = no;
this.Name = name;
} public static LoopLink Cursor { get; set; } /// <summary>
/// 添加
/// </summary>
/// <param name="head">链表头</param>
/// <param name="addNode">所要添加节点</param>
public static void Add(ref LoopLink head, LoopLink addNode)
{
if (head.Next == null)
{
head = addNode;
head.Next = addNode;
Cursor = head;
}
else
{
Cursor.Next = addNode;
addNode.Next = head;
Cursor = Cursor.Next;
}
} /// <summary>
/// 删除节点
/// </summary>
/// <param name="head">链表头</param>
/// <param name="no">所要删除编号</param>
public static void Remove(ref LoopLink head, int no)
{
LoopLink cur = head; while (true)
{
if (cur.Next.No == no)
{
cur.Next = cur.Next.Next;
return;
}
cur = cur.Next;
}
} /// <summary>
/// 输入信息(重写ToString方法)
/// </summary>
/// <returns></returns>
public override string ToString()
{
return "No---> " + No + " Name---> " + Name;
}
}
扩展训练(面试题)
题目:有一颗炸弹,有N个人围成一个圆形,从第K个人开始数数,数M就退出圆。最后算出留下来要被炸死是第几个人。请用代码实现。
代码如下:
//N个人
int n = ; //第K个人开始数数
int k = ; //数到M就退出
int m = ; Game head = new Game(); //构建一个由N个人组成的圆形
Game.Add(ref head, n);
//查找谁会被炸死
Game.Bomb(ref head, k, m); /// <summary>
/// 游戏类
/// </summary>
public class Game
{
public int No { get; set; } public Game Next { get; set; } public Game() { } public Game(int no)
{
this.No = no;
} public static void Add(ref Game head, int n)
{
Game cursor = null;
for (int i = ; i < n; i++)
{
Game temp = new Game(i+);
if (i == )
{
head.Next = temp;
head = temp;
cursor = head;
}
else
{
cursor.Next = temp;
temp.Next = head;
cursor = cursor.Next;
}
}
} /// <summary>
/// 查找谁会被炸死
/// </summary>
/// <param name="head">链表头</param>
/// <param name="k">开始数数的人</param>
/// <param name="m">数几就退出圆圈</param>
public static void Bomb(ref Game head,int k, int m)
{
Game tail = head; //拿到最后一个节点
while (!Object.ReferenceEquals(tail.Next,head))
{
tail = tail.Next;
} //从第K个人开始数数
for (int i = ; i < k; i++)
{
head = head.Next;
tail = tail.Next;
} //当头跟尾是同一个节点说明找到最终的节点
int mark = ;
while (!object.ReferenceEquals(tail,head))
{
for (int i = ; i < m-; i++)
{
head = head.Next;
tail = tail.Next;
} Console.WriteLine(@"第"+mark+@"个安全退出人的编号:"+head.No); head = head.Next;
tail.Next = head;
mark++;
} Console.WriteLine(@"最后被炸死人的编号:" + head.No);
}
}
总结:
1.扩展训练题其实考的就是环形链表,这个题目跟约瑟夫问题是一样的(实现思路是一样的)
2.“程序=算法+数据结构”,但是在我们真正开发的时候算法和数据结构用到很少,一般比较大型项目或者复杂度比较高项目和游戏里面可能才会用到这些,但是我们还是要了解,说不定面试考到了呢?(答对了会加分的哦!^_^)
3.链表什么时候会用到呢?比如说象棋里面有悔棋,我们就可以用双向链表来实现,这样就可以悔到上一步也可以下一步了,还有很多应用场景。而单链表的话像LinkedList就是用单链表实现的(但是LinkedList被List代替,不推荐用LinkedList,推荐用List.自己查一下为什么?)
(本人学识有限,文章如有误,愿见谅。希望能指出来,以免误人子弟了。^_^)
C# 数据结构 - 单链表 双链表 环形链表的更多相关文章
- 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II
[算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...
- 数据结构与算法——链表 Linked List(单链表、双向链表、单向环形链表-Josephu 问题)
链表是有序的列表,但是在内存中存储图下图所示 链表是以 节点 的方式来存储,是 链式存储 每个节点包含 data 域.next 域,指向下一个节点 链表的各个节点 不一定是连续存储,如上图所示 链表还 ...
- 图解Java数据结构之环形链表
本篇文章介绍数据结构中的环形链表. 介绍 环形链表,类似于单链表,也是一种链式存储结构,环形链表由单链表演化过来.单链表的最后一个结点的链域指向NULL,而环形链表的建立,不要专门的头结点,让最后一个 ...
- 代码随想录第四天| 24. 两两交换链表中的节点 、19.删除链表的倒数第N个节点 、160.链表相交、142.环形链表II
今天链表致死量 第一题 public static class ListNode { int val; ListNode next; ListNode() {} ListNode(int val) { ...
- 【LeetCode题解】141_环形链表
目录 141_环形链表 描述 解法一:哈希表 思路 Java 实现 Python 实现 解法二:双指针(龟兔算法) 思路 Java 实现 Python 实现 141_环形链表 描述 给定一个链表,判断 ...
- java数据结构——单链表、双端链表、双向链表(Linked List)
1.继续学习单链表,终于摆脱数组的魔爪了,单链表分为数据域(前突)和引用域(指针域)(后继),还有一个头结点(就好比一辆火车,我们只关心火车头,不关心其它车厢,只需知晓车头顺藤摸瓜即可),头结点没有前 ...
- php实现单,双向链表,环形链表解决约瑟夫问题
传智播客PHP学院 韩顺平 PHP程序员玩转算法第一季 http://php.itcast.cn 聊天篇: 数学对我们编程来说,重不重要? 看你站在什么样的层次来说. 如果你应用程序开发,对数学要求 ...
- python实现数据结构单链表
#python实现数据结构单链表 # -*- coding: utf-8 -*- class Node(object): """节点""" ...
- C语言数据结构-单链表的实现-初始化、销毁、长度、查找、前驱、后继、插入、删除、显示操作
1.数据结构-单链表的实现-C语言 typedef struct LNode { int data; struct LNode* next; } LNode,*LinkList; //这两者等价.Li ...
随机推荐
- Jenkins+Git+Docker+K8s部署
准备工作 Jenkins已安装 Docker和K8s部署运行成功 代码管理工具使用Git 最近公司项目使用Jenkins+Git+Docker+K8s进行持续化构建部署,这里笔者整理了一下构建部署的相 ...
- Maven - StackOverflowError
问题与分析 今天发现服务器上的Jenkins在集成项目时报错,报错原因如下: error compiling: java.lang.StackOverflowError -> [Help 1] ...
- Python命名空间和作用域
准备知识: 1.在Python解释器开始执行之后,机会在内存中开辟一个空间,每当遇到 一个变量的时候,就把变量和值之间的关系记录下来,但是当遇到函数定义 的时候,解释器只是把函数名读入内存,表示这个函 ...
- 遇到的一些vue的问题
一.事件绑定中的事件处理方法后加不加括号问题 1.例如: click事件后加不加括号 a.@click = "getContent" b.@click = "getCon ...
- AD7606笔记
V1~V8共8个ADC通道: REFIN/OUT:基准电源,可选择内部(REF_SLECT=1)的或者外部的(REF_SLECT=0) VDIRVE:MCU的的VCC,2.3~5V.逻辑电平指的是需要 ...
- 通过sqlserver sa密码修改windows操作系统密码
如果你不记得windows管理员的密码了,但知道sqlserver sa用户的密码,可以通过以下方式修改: 进入SQL之后执行以下语句: -- 允许配置高级选项 EXEC sp_configure ...
- Exception in thread "main" java.lang.UnsupportedClassVersionError: com/google/common/base/Function : Unsupported major.minor version 52.0的解决办法(图文详解)
不多说,直接上干货! 问题详情 Exception in thread "main" java.lang.UnsupportedClassVersionError: com/goo ...
- 机器学习框架ML.NET学习笔记【9】自动学习
一.概述 本篇我们首先通过回归算法实现一个葡萄酒品质预测的程序,然后通过AutoML的方法再重新实现,通过对比两种实现方式来学习AutoML的应用. 首先数据集来自于竞赛网站kaggle.com的UC ...
- 【0 基础学Dojo】第【1】篇 HelloWord
打开dojo 官网首页 http://dojotoolkit.org/,我们看到 点击get dojo 你将得到下载Dojo 的不同方式 2,点击下面方式下载, 解压后 新建myTest.html, ...
- 数据库(数据库、表及表数据、SQL语句)
数据库MYSQL 今日内容介绍 u MySQL数据库 u SQL语句 第1章 数据库 1.1 数据库概述 l 什么是数据库 数据库就是存储数据的仓库,其本质是一个文件系统,数据按照特定的格式将数据存储 ...