双向循环链表的Java版本实现
- 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版本实现的更多相关文章
- 3.1、双向循环链表(java实现)
1.创建节点类 public class CNode<T> { public CNode prev; public CNode next; public T data; public CN ...
- java与数据结构(4)---java实现双向循环链表
线性表之链式存储结构双向循环链表 双向循环链表:每个结点包含了数据.直接前驱地址指针和直接后驱地址指针,头结点的直接前驱指向尾结点,尾结点的直接后驱指向头结点,头尾相连构成一个可正可反的圆环.可以形象 ...
- java实现双向循环链表
java实现循环链表:http://www.cnblogs.com/lixiaolun/p/4643911.html 在单链表中,查询下一个元素的时间是O(1).查询上一个元素的时间却是O(n). 为 ...
- (java实现)双向循环链表
什么是双向循环链表 在了解双向循环链表之前,如果对链表还没有一个清晰的概念,建议你看看单链表和单向循环链表,这有利于你更好的理解下面的内容.(废话有点多[逃] 相比单链表,双向循环链表是一个更加复杂的 ...
- Java 用双向循环链表实现 遍历
package day2; /** * 构建双向循环链表,实现遍历功能 */public class DoubleLB { public static void main(String[] args) ...
- java数据结构-06双向循环链表
双向循环链表跟单向链表一样,都是头尾相连,不过单向是尾指向头,双向是头尾互相指,可以从前往后查,也可以从后往前查 无头结点的双向循环链表 public class CircleLinkedList&l ...
- C语言通用双向循环链表操作函数集
说明 相比Linux内核链表宿主结构可有多个链表结构的优点,本函数集侧重封装性和易用性,而灵活性和效率有所降低. 可基于该函数集方便地构造栈或队列集. 本函数集暂未考虑并发保护. 一 ...
- "《算法导论》之‘线性表’":双向循环链表
本文双链表介绍部分参考自博文数组.单链表和双链表介绍 以及 双向链表的C/C++/Java实现. 1 双链表介绍 双向链表(双链表)是链表的一种.和单链表一样,双链表也是由节点组成,它的每个数据结点中 ...
- Linux内核2.6.14源码分析-双向循环链表代码分析(巨详细)
Linux内核源码分析-链表代码分析 分析人:余旭 分析时间:2005年11月17日星期四 11:40:10 AM 雨 温度:10-11度 编号:1-4 类别:准备工作 Email:yuxu97101 ...
随机推荐
- Some useful links
Integrating the FlyCapture SDK for use with OpenCV CStereoGrabber_Bumblebee.h OpenCV with PGR Flycap ...
- EasyUI组件(窗口组件)
注意首先要在title后面导入配置文件,前后顺序不能乱 <!-- 1.jQuery的js包 --><script type="text/javascript" s ...
- Java I/O Basic
/* 记住每个类相应的用法*/流的分类: io包内定义了所有的流 分类: 方向:输入流.输出流 处理数据单位:字节流.字符流 功能不同:节点流.处理流 所有流类型,位于java.io包内,分别继承以下 ...
- E: dpkg 被中断,您必须手工运行 sudo dpkg --configure -a 解决此问题。
学习 : http://blog.csdn.net/darennet/article/details/9009361 http://www.uedsc.com/dpkg-sudo-dpkg-confi ...
- Thinkphp框架感悟(一)
一.assign() /** * 分析: * 此处是Controller类里面的assign方法,我们一般写的控制器所调用的assign方法就是调的这个. * 而这个方法就干了三件事:1.获取传过来的 ...
- github 离线版本下载
http://download.csdn.net/download/nevinblog/9031049
- 《JAVA开发环境的熟悉》实验报告——20145337
- BizTalk开发系列(二十三) BizTalk性能指标参考
BizTalk项目目前比较少,使用的客户也不多.大多只知道BizTalk是一个不错的产品,是Microsoft SOA平台的核心产品,不过还没有将其应用到生产环境.还有一些客户对BizTalk的性能不 ...
- Win8.1屏幕亮度自动调节关闭方法
细心的朋友会发现,Win8.1系统的笔记本屏幕亮度有时候,会根据外界光线亮度以及温度自动调节屏幕亮度,尽管看似比较智能,但有时候我们并不希望笔记本屏幕亮度受光线影响,忽暗忽亮.如果我们希望Win8笔记 ...
- linux应用与发展(上)
UNIX/Linux发展历史 当年,没有cmm的概念,也没什么PMP认证什么的,导致了MIT,GE,AT&T联合开发multics失败,multics是一个复杂多功能的操作系统.开发者想要开发 ...