Java数据结构——循环链表
一、单向循环链表
表中的最后一个节点的指针域指向头结点,整个链表形成一个环。其他的与单链表相同。
(以下图片均来自网络,侵删)

插入操作

删除操作

简单实现
public class CiNode {
private Object data;
private CiNode next;
private static CiNode first; // 临时结点,头结点,并不是链表里想要的值,起到标记链表头的作用
public CiNode() {
super();
}
public CiNode(Object data, CiNode next) {
super();
this.data = data;
this.next = next;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public CiNode getNext() {
return next;
}
public void setNext(CiNode next) {
this.next = next;
}
public static void add(CiNode node, int index) {
if (index == 0) {
node.next = first.next;
first.next = node;
} else {
int temp = 0;
for (CiNode n = first.next;; n = n.next) {
temp++;
if (temp == index) {
node.next = n.next;
n.next = node;
break;
}
}
}
}
public static void remove(int index) {
if (index % 5 == 0) { // 删除第一个元素,考虑循环
first.next = first.next.next;
} else {
int temp = 0;
for (CiNode n = first.next;; n = n.next) {
if (n == first) {
temp -= 1; // 减一是因为链表循环计数时会把first记一次,所以这里减一次,使下标一致
}
temp++;
if (temp == index) {
n.next = n.next.next;
break;
}
}
}
}
public static void display() {
for (CiNode n = first.next; n != first; n = n.next) {
System.out.print(n.data + " ");
}
System.out.println();
}
public static void main(String[] args) {
CiNode node4 = new CiNode("ddd", null);
CiNode node3 = new CiNode("ccc", node4);
CiNode node2 = new CiNode("bbb", node3);
CiNode node1 = new CiNode("aaa", node2);
first = new CiNode(null, node1);
node4.next = first;
System.out.println("当前链表:");
display();
add(new CiNode("eee", null), 5); // 传5进去是为了体现循环,当参数大于了链表长度时,又回到first
System.out.println("插入后链表:");
display();
remove(11);
System.out.println("删除后链表:");
display();
}
}
循环单链表模拟击鼓传花游戏
public class JiGuChuanHua implements Runnable {
private Object person;//游戏的人的data
private JiGuChuanHua next;//指向下一个人,
private static JiGuChuanHua first;//第一个人
public JiGuChuanHua() {
super();
}
//构造方法
public JiGuChuanHua(Object person, JiGuChuanHua next) {
super();
this.person = person;
this.next = next;
}
@Override
public void run() {
JiGuChuanHua loser = first; //以第一个人为起点
double time = (Math.random() + 0.5) * 10; //随机产生游戏时间(5-15s)
boolean flag = true;//结束线程的标志
System.out.println("本局游戏时间:" + time + "s");
System.out.println("游戏开始:");
System.out.println(loser.person);//初始游戏时,花在第一个人手上,打印
double startTime = System.currentTimeMillis();//获取开始游戏的时间
while (flag) {
for (JiGuChuanHua node = first;; node = node.next) {
loser = node.next;//loser指向下一个人,模拟传花过程
System.out.println(loser.person);//打印拿到花的人
try {
Thread.sleep((long) (Math.random() * 500));//线程睡眠,模拟花在每一个人手中停留时间
} catch (InterruptedException e) {
e.printStackTrace();
}
double endTime = System.currentTimeMillis();//传完一个人时的时间
if (endTime - startTime >= time * 1000) {//游戏时间到,这里不具备原子性,所以是大于等于
flag = false;//标志位置为false
break;
}
}
}
System.out.println("游戏结束,拿到花的人是:" + loser.person);//打印最后拿到花的人
}
public static void main(String[] args) {
//将参加游戏的人用链表连起来,构成一个循环
JiGuChuanHua person5 = new JiGuChuanHua("e", null);
JiGuChuanHua person4 = new JiGuChuanHua("d", person5);
JiGuChuanHua person3 = new JiGuChuanHua("c", person4);
JiGuChuanHua person2 = new JiGuChuanHua("b", person3);
JiGuChuanHua person1 = new JiGuChuanHua("a", person2);
person5.next = person1;
first = person1;
JiGuChuanHua jgch = new JiGuChuanHua();
Thread thread = new Thread(jgch);
thread.start(); //开启线程
}
}
二、双向循环链表
从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

插入操作

删除操作

简单实现
public class CiDlNode {
private Object data;
private CiDlNode next;
private CiDlNode prev;
private static CiDlNode first;
public CiDlNode() {
super();
}
public CiDlNode(Object data, CiDlNode next, CiDlNode prev) {
super();
this.data = data;
this.next = next;
this.prev = prev;
}
public static void insert(Object data, int index) {
CiDlNode node = new CiDlNode(data, null, null);
if (index == 0) {
node.next = first.next;
first.next.prev = node;
first.next = node;
node.prev = first;
} else {
int temp = 0;
for (CiDlNode n = first.next;; n = n.next) {
temp++;
if (temp == index) {
node.next = n.next;
node.next = n.next;
n.next.prev = node;
n.next = node;
node.prev = n;
break;
}
}
}
}
public static void remove(Object data) {
for (CiDlNode n = first.next; n != first; n = n.next) {
if (n.data.equals(data)) {
n.prev.next = n.next;
n.next.prev = n;
}
}
}
public static void print() {
for (CiDlNode node = first.next; node != first; node = node.next) {
System.out.print(node.data + " ");
}
System.out.println();
}
public static void main(String[] args) {
first = new CiDlNode("0", null, null);
CiDlNode node1 = new CiDlNode("aaa", null, first);
CiDlNode node2 = new CiDlNode("bbb", null, node1);
CiDlNode node3 = new CiDlNode("ccc", null, node2);
CiDlNode node4 = new CiDlNode("ddd", first, node3);
node3.next = node4;
node2.next = node3;
node1.next = node2;
first.next = node1;
System.out.println("当前链表:");
print();
insert("ddd", 5);
System.out.println("插入后链表:");
print();
remove("ddd");
System.out.println("删除后链表:");
print();
}
}
Java数据结构——循环链表的更多相关文章
- Java数据结构——循环链表的实现
//单链表结点类 public class Node<T> { //单链表结点类,T指定结点的元素类型 public T data; //数据域,保存数据元素 public Node< ...
- java与数据结构(3)---java实现循环链表
循环链表:将单链表中尾结点的指针由空指针改为指向头结点,就使整个单链表形成一个环,这种首尾相接的单链表称为单链表循环表,即循环链表. 循环链表与单链表最重要的区别是:尾结点的指针,不再是p->n ...
- Java数据结构之队列的实现以及队列的应用之----简单生产者消费者应用
Java数据结构之---Queue队列 队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在 ...
- Java数据结构之线性表(2)
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
- Java数据结构之线性表
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
- Java数据结构和算法(一)线性结构
Java数据结构和算法(一)线性结构 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 线性表 是一种逻辑结构,相同数据类型的 ...
- JAVA数据结构系列 栈
java数据结构系列之栈 手写栈 1.利用链表做出栈,因为栈的特殊,插入删除操作都是在栈顶进行,链表不用担心栈的长度,所以链表再合适不过了,非常好用,不过它在插入和删除元素的时候,速度比数组栈慢,因为 ...
- Java数据结构之树和二叉树(2)
从这里始将要继续进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来 ...
- Java数据结构之树和二叉树
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
随机推荐
- intel:spectre&Meltdown侧信道攻击(四)—— cache mapping
前面简单介绍了row hammer攻击的原理和方法,为了更好理解这种底层硬件类攻击,今天介绍一下cpu的cache mapping: 众所周知,cpu从内存读数据,最开始用的是虚拟地址,需要通过分页机 ...
- LeetCode刷题时引发的思考:Java中ArrayList存放的是值还是引用?
好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 今天我在刷LeetCode ...
- 4.深入k8s:容器持久化存储
从一个例子入手PV.PVC Kubernetes 项目引入了一组叫作 Persistent Volume Claim(PVC)和 Persistent Volume(PV)的 API 对象用于管理存储 ...
- 【AHOI2009】中国象棋 题解(线性DP+数学)
前言:这题主要是要会设状态,状态找对了问题迎刃而解. --------------------------- 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可 ...
- 银弹谷零代码开发V百科|使用技巧:Vbase技巧二则之二
银弹谷零代码开发V百科|使用技巧:Vbase技巧二则之二 结构树设置 Vbase系统提供机构树默认展开层级和加载模式的设置. sa账号登录,默认密码8. 打开机构与权限管理—机构初始化设置菜单,选择“ ...
- CustomPlot 在Qt下 鼠标点击曲线 显示当前坐标
此次记录主要是为了下次使用时能回忆起来才做得笔记,若有需改进的地方,请不吝珠玉. widget.cpp #include "widget.h" #include "ui_ ...
- 最新版 源码编译 docker
前言: 最近想研究 docker 源码,那么要研究源码第一步就是学会通过源码编译.然后在网上查找了很多,都是比较老的版本.目前官最新的版本是 18.09.经过一番探索之后,终于成功编译了 下面我把我的 ...
- stat 命令家族(1)- 详解 vmstat
性能测试必备的 Linux 命令系列,可以看下面链接的文章哦 vmstat 介绍 Virtual Meomory Statistics,报告虚拟内存统计信息 会统计进程信息.内存.交换区.IO.磁盘. ...
- Android ExpandListView的用法(补上昨天的)(今天自习)
今天自习写ExpandListView的作业,昨天没写博客就是去写作业去了. 今天来说昨天内容吧! 其实ExpandListView和ListView的用法大同小异. 首先就是创建一个自己的适配器(现 ...
- CSS品控与流程
精通CSS意味着不仅能写出可用的标记和样式,还能让代码好阅读.方便移植.易维护. 1.外部代码质量:调试CSS 外部代理质量就是用户能体验到的最终结果.主要体现在几个方面. 正确性.CSS属性名都写对 ...