• 单向循环链表
  • 双向循环链表
  • 仿真链表

一、单向循环链表:

1、概念:

单向循环链表是单链表的另一种形式,其结构特点是链表中最后一个结点的指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个

和单链表相比,循环单链表的长处是从链尾到链头比较方便。当要处理的数据元素序列具有环型结构特点时,适合于采用循环单链表。

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

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

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

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

2、单链表的代码实现:

先回顾上一篇文章,定位到第三段“三、单项链表的代码实现”,我们是需要修改这段里面的(3)LinkList.java代码,(1)和(2)的代码不变。

(3)LinkList.java:单项循环链表类:(核心代码)

 //单向循环链表类
public class CycleLinkList implements List { Node head; //头指针
Node current;//当前结点对象
int size;//结点个数 //初始化一个空链表
public CycleLinkList()
{
//初始化头结点,让头指针指向头结点。并且让当前结点对象等于头结点。
this.head = current = new Node(null);
this.size =0;//单向链表,初始长度为零。
this.head.next = this.head;
} //定位函数,实现当前操作对象的前一个结点,也就是让当前结点对象定位到要操作结点的前一个结点。
//比如我们要在a2这个节点之前进行插入操作,那就先要把当前节点对象定位到a1这个节点,然后修改a1节点的指针域
public void index(int index) throws Exception
{
if(index <-1 || index > size -1)
{
throw new Exception("参数错误!");
}
//说明在头结点之后操作。
if(index==-1) //因为第一个数据元素结点的下标是0,那么头结点的下标自然就是-1了。
return;
current = head.next;
int j=0;//循环变量
while(current != head&&j<index)
{
current = current.next;
j++;
} } @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.setNext(current.next.next);
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.getElement();
} @Override
public void insert(int index, Object obj) throws Exception {
// TODO Auto-generated method stub
if(index <0 ||index >size)
{
throw new Exception("参数错误!");
}
index(index-1);//定位到要操作结点的前一个结点对象。
current.setNext(new Node(obj,current.next));
size++;
} @Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return size==0;
}
@Override
public int size() {
// TODO Auto-generated method stub
return this.size;
} }

14行是添加的代码,30行是修改的代码。

3、单项循环链表的应用举例:

编写击鼓传花小游戏。

游戏规则:N个人围成一个圈,从第一个人开始传花,当数到M时,该人退出游戏,直到剩下最后一个人。

代码实现:

(4)Game.java:

 //游戏类
public class Game { //单向循环链表
CycleLinkList list = new CycleLinkList();
//总人数
int num;
//数到几退出
int key; //游戏初始化方法
public Game(int num,int key)
{
this.num = num;
this.key = key;
} public void play() throws Exception
{
for(int i=0;i<num;i++)
{
list.insert(i, i);
} System.out.println("\n-------游戏开始之前---------\n");
for(int i=0;i<list.size;i++)
{
System.out.print(list.get(i)+" ");
}
System.out.println("\n-------游戏开始---------\n");
int iCount=num; //开始等于总人数num
int j=0; //累加器,计算是否能被key整除。 Node node = list.head;
while(iCount!=1)
{
if(node.getElement()!=null&& Integer.parseInt(node.getElement().toString())!=-1)
{
j++;
if(j%key==0)
{
node.setElement(-1);
iCount--;
System.out.println();
for(int i=0;i<list.size;i++)
{
System.out.print(list.get(i)+" ");
}
}
}
node = node.next;
}
System.out.println("\n-------游戏结束---------\n");
for(int i=0;i<list.size;i++)
{
System.out.print(list.get(i)+" ");
}
} }

(5)Test.java:

 public class Test {

     /**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
/*
CycleLinkList list = new CycleLinkList();
for(int i=0;i<10;i++)
{
int temp = ((int)(Math.random()*100))%100;
list.insert(i, temp);
System.out.print(temp+" ");
}
list.delete(4);
System.out.println("\n------删除第五个元素之后-------");
for(int i=0;i<list.size;i++)
{
System.out.print(list.get(i)+" ");
}*/ Game game = new Game(10,3);
game.play(); }
}

二、双向循环链表:

双向链表:

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

双向循环链表:

  在双向链表中,每个结点包括三个域,分别是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表示要插入的结点,①、②、③、④表示实现插入过程的步骤:

循环双向链表的删除过程:

  下图中的指针p表示要插入结点的位置,①、②表示实现删除过程的步骤:

2、双向循环链表的代码实现:

(1)List.java:

 //线性表接口
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;
}

(2)Node.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();
}
}

(3)DoubleCycleLinkList.java:

 //单向链表类
public class DoubleCycleLinkList implements List { Node head; //头指针
Node current;//当前结点对象
int size;//结点个数 //初始化一个空链表
public DoubleCycleLinkList() {
//初始化头结点,让头指针指向头结点。并且让当前结点对象等于头结点。
this.head = current = new Node(null);
this.size = 0;//单向链表,初始长度为零。
this.head.next = head;
this.head.prior = head;
} //定位函数,实现当前操作对象的前一个结点,也就是让当前结点对象定位到要操作结点的前一个结点。
public void index(int index) throws Exception {
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 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.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.getElement();
} @Override
public void insert(int index, Object obj) throws Exception {
// TODO Auto-generated method stub
if (index < 0 || index > size) {
throw new Exception("参数错误!");
}
index(index - 1);//定位到要操作结点的前一个结点对象。
current.setNext(new Node(obj, current.next));
current.next.setPrior(current);
current.next.next.setPrior(current.next); size++;
} @Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return size == 0;
} @Override
public int size() {
// TODO Auto-generated method stub
return this.size;
} }

(4)Test.java:

 public class Test {

     /**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
DoubleCycleLinkList list = new DoubleCycleLinkList();
for (int i = 0; i < 10; i++) {
int temp = ((int) (Math.random() * 100)) % 100;
list.insert(i, temp);
System.out.print(temp + " ");
}
list.delete(4);
System.out.println("\n------删除第五个元素之后-------");
for (int i = 0; i < list.size; i++) {
System.out.print(list.get(i) + " ");
}
} }

运行效果:

三、仿真链表:

在链式存储结构中,我们实现数据元素之间的次序关系依靠指针。我们也可以用数组来构造仿真链表。方法是在数组中增加一个(或两个)int类型的变量域,这些变量用来表示后一个(或前一个)数据元素在数组中的下标。我们把这些int类型变量构造的指针称为仿真指针。这样,就可以用仿真指针构造仿真的单链表(或仿真的双向链表)。

数据结构Java实现04----循环链表、仿真链表的更多相关文章

  1. 数据结构java(一)数组链表

    链表是数据结构中最基础的内容,链表在存储结构上分成两种:数组形式储存,链式存储. 相比c语言需要的结构体,在java中由于有了面向对象编程,将指针‘藏’了起来,不需要分配内存. 所以只需要创建一个对象 ...

  2. 纯数据结构Java实现(5/11)(Set&Map)

    纯数据结构Java实现(5/11)(Set&Map) Set 和 Map 都是抽象或者高级数据结构,至于底层是采用树还是散列则根据需要而定. 可以细想一下 TreeMap/HashMap, T ...

  3. [Java 教程 04] Java基础语法

    在上一篇文章中我们已经运行了个简单的java程序,但是没有给大家讲解代码部分的内容与含义.学习,我们要做到知其然而知其所以然,所以本篇文章我们就来讲解java程序的基本语法,学完这篇文章你再回头看上篇 ...

  4. 024 01 Android 零基础入门 01 Java基础语法 03 Java运算符 04 关系运算符

    024 01 Android 零基础入门 01 Java基础语法 03 Java运算符 04 关系运算符 本文知识点:Java中的关系运算符 关系运算符

  5. 004 01 Android 零基础入门 01 Java基础语法 01 Java初识 04 Java程序的结构

    004 01 Android 零基础入门 01 Java基础语法 01 Java初识 04 Java程序的结构 Java程序的结构 Java程序外层--类 程序外层,如下面的代码,是一个类的定义. c ...

  6. 111 01 Android 零基础入门 02 Java面向对象 04 Java继承(上)02 继承的实现 01 继承的实现

    111 01 Android 零基础入门 02 Java面向对象 04 Java继承(上)02 继承的实现 01 继承的实现 本文知识点: 继承的实现 说明:因为时间紧张,本人写博客过程中只是对知识点 ...

  7. java数据结构和算法04(链表)

    前面我们看了数组,栈和队列,大概就会这些数据结构有了一些基本的认识,首先回顾一下之前的东西: 在数组中,其实是分为有序数组和无序数组,我简单实现了无序数组,为什么呢?因为有序数组的实现就是将无序数组进 ...

  8. 数据结构Java实现03----单向链表的插入和删除

    文本主要内容: 链表结构 单链表代码实现 单链表的效率分析 一.链表结构: (物理存储结构上不连续,逻辑上连续:大小不固定)            概念: 链式存储结构是基于指针实现的.我们把一个数据 ...

  9. 数据结构Java实现02----单向链表的插入和删除

    文本主要内容: 链表结构 单链表代码实现 单链表的效率分析 一.链表结构: (物理存储结构上不连续,逻辑上连续:大小不固定)            概念: 链式存储结构是基于指针实现的.我们把一个数据 ...

随机推荐

  1. R语言归一化处理

    归一化化就是要把你需要处理的数据经过处理后(通过某种算法)限制在你需要的一定范围内.首先归一化是为了后面数据处理的方便,其次是保正程序运行时收敛加快. R语言中的归一化函数:scale 数据归一化包括 ...

  2. [js开源组件开发]js手机端浮层控件,并有多种弹出小提示,兼容pc端浏览器

    js dialog组件,包含alert和confirm的实现 本组件所有的资源均在github上可以查看源代码 GitHub 本dialog的组件的例子请在这里查看 demo dialog js di ...

  3. javascript获取url信息的常见方法

    先以"http://www.cnblogs.com/wuxibolgs329/p/6188619.html#flag?test=12345"为例,然后获得它的各个组成部分. 1.获 ...

  4. DOM性能小记

    在使用DOM操作时,同样的效果用不同的方式来实现,性能方面也会有很大的差异.尤其在移动式设备上,资源本来就很有限,一旦DOM写不好的话操作就会非常卡顿.这个周末,就写个DOM性能小记吧.错漏之处,望多 ...

  5. SAP 金额在表中的存储及货币转换因子

    场景:一个接口出问题了,SAP通过RFC将SO数据传输到Java系统,错误的将100日元传为1.00日元. 其实查看SAP透明表发现,表中存储的的确是1.00,是前台真实数据的1/100,开发接口时没 ...

  6. 利用Android多进程机制来分割组件

    android对于内存有一定的限制,很多手机上对内存的限制是完全不同的.我们的应用程序其实就是一个进程,这个进程是完全独立的,这个进程分配的内存是一定的,所以我们经常会遇到OOM的问题.但,你可能不知 ...

  7. Android项目实战(十五):自定义不可滑动的ListView和GridView

    不可滑动的ListView (RecyclweView类似) public class NoScrollListView extends ListView { public NoScrollListV ...

  8. Android 优秀的开源框架整理

    第一部分:系统架构 thinkAndroid https://github.com/white-cat/ThinkAndroid ThinkAndroid是一个免费的开源的.简易的.遵循Apache2 ...

  9. iOS 删除 Main.storyboard 和 LaunchScreen.storyboard

    第一步: 右键选中Main.storyboard —- delete —— Move to Trash LaunchScreen同理 第二步 点击工程名,就是最顶级目录 右侧出现general选项卡 ...

  10. HTML列表元素

    HTML定义了3类列表: 1.有序列表(通常用数字编号) 2.无序列表(通常前面加原点) 3.自定义列表(列表项目,带有集成的定义) 有序列表和无序列表均为列表中的每一项使用列表项元素(<li& ...