线性表之链式存储结构双向循环链表

双向循环链表:每个结点包含了数据、直接前驱地址指针和直接后驱地址指针,头结点的直接前驱指向尾结点,尾结点的直接后驱指向头结点,头尾相连构成一个可正可反的圆环。可以形象的理解成一群孩子手拉手牵成一个圆圈,从头一个孩子开始可以从左往右报数,也可以从右往左开始报数。

优点:双向循环链表可以迅速的获取当前数据的前驱数据,解决了单向循环链表从头开始遍历的麻烦。

接口类

 package list;

 public interface Listable<T> {

     public void clear();

     public boolean isEmpty();

     public int Length();

     public T getElement(int index);

     public boolean add(T element);

     public boolean addHead(T element);

     public boolean addByIndex(int index, T element);

     public boolean add(Listable<T> list);

     public T remove(int index);

     public boolean removeAll();

     public T remove(T element);

     public T setElement(int index,T element);

 }

结点类

 //结点类
class Node<T> {
private Node<T> left,right;
private T data; Node(T data) {
this(data,null,null);
} Node() {
this(null,null,null);
} Node(T data,Node<T> left,Node<T> right) {
this.data = data;
this.left = left;
this.right = right;
} public T getData() {
return this.data;
} public Node<T> getLeft() {
return this.left;
} public Node<T> getRight() {
return this.right;
} public void setData(T data) {
this.data = data;
} public void setRight(Node<T> right) {
this.right = right;
} public void setLeft(Node<T> left) {
this.left = left;
} public String toString() {
return getData().toString();
}
}

接口实现类

 //接口实现类
class DoubleLinkedList<T> implements Listable<T> {
public Node<T> head; //建空表,带头结点
DoubleLinkedList() {
this(null);
} //建表,带头结点,表中有一条数据元素
DoubleLinkedList(T element) {
if(element == null) {
head = new Node<T>(element,null,null);
head.setRight(head);
head.setLeft(head);
}else {
Node<T> headRight = new Node<T>(element,null,null);
head = new Node<T>(null,headRight,headRight);
headRight.setLeft(head);
headRight.setRight(head);
}
} //清空当前链表
public void clear() {} //判空表
public boolean isEmpty() {
return head.getRight() == head;
} //表长
public int Length() {
int len = 0;
Node<T> temp = head;
while(temp.getRight() != head) {
len++;
temp = temp.getRight();
}
return len;
} //取下标index处的数据
public T getElement(int index) {
if(index <= 0) {
return head.getRight().getData();
}
int len = Length();
if(index >= len) {
return head.getLeft().getData();
}
T element = null;
if(index > 0 && index < len) {
int k = 0;
Node<T> temp = head;
//此处只能用while不能用if,用错好几次
while(k <= index && temp.getRight() != head) {
k++;
temp = temp.getRight();
}
element = temp.getData();
}
return element;
} //尾添
public boolean add(T element) {
if(element == null) return false;
Node<T> node = new Node<T>(element,head.getLeft(),head);
head.getLeft().setRight(node);
head.setLeft(node);
return true;
} //首添
public boolean addHead(T element) {
if(element == null) return false;
Node<T> node = new Node<T>(element,head,head.getRight());
head.getRight().setLeft(node);
head.setRight(node);
return false;
} //表index处,添加新数据element
public boolean addByIndex(int index, T element) {
if(index <= 0) {
return addHead(element);
}else if(index >= Length()) {
return add(element);
}else {
int k = 0;
Node<T> temp = head;
//此处只能用while不能用if,用错好几次
while(k <= index && temp.getRight() != head) {
k++;
temp = temp.getRight();
}
Node<T> node = new Node<T>(element,temp.getLeft(),temp);
temp.getLeft().setRight(node);
temp.setLeft(node);
}
return true;
} //将参数中的链表添加到当前链表的尾部
public boolean add(Listable<T> slist) {
if(slist.isEmpty() || slist == null) return false;
if(slist instanceof DoubleLinkedList) {
DoubleLinkedList<T> list = (DoubleLinkedList<T>)slist;
//以下操作影响到了添加的slist表,所以需要将slist表重新备份一个
DoubleLinkedList<T> temp = new DoubleLinkedList<T>();
for(int i = 0; i < list.Length(); i++) {
temp.add(list.getElement(i));
}
Node<T> node = temp.head;
Node<T> nodeLeft = node.getLeft();
Node<T> nodeRight = node.getRight();
this.head.getLeft().setRight(node.getRight());
nodeRight.setLeft(this.head.getLeft());
nodeLeft.setRight(this.head);
this.head.setLeft(node.getLeft());
return true;
}else {
return false;
}
} //删除下标Index处的数据
public T remove(int index) {
if(isEmpty()) return null;
if(index < 0) {
index = 0;
}
int len = Length();
if(index >= len) {
//当index大于或等于表长是,默认移走表的最后一个元素,即下标为len-1的数据
index = len-1;
}
T element = null;
if(index >= 0 && index < len) {
Node<T> temp = head;
int k = 0;
while(k <= index && temp.getRight() != head) {
k++;
temp = temp.getRight();
}
element = temp.getData();
temp.getRight().setLeft(temp.getLeft());
temp.getLeft().setRight(temp.getRight());
temp.setRight(null);
temp.setLeft(null);
temp = null;
}
return element;
} //删除当前链表中所有的数据,只剩头结点
public boolean removeAll() {
if(isEmpty()) return false;
Node<T> temp = head.getRight();
while(temp != head) {
head.setRight(temp.getRight());
temp.getRight().setLeft(head);
temp.setLeft(null);
temp.setRight(null);
temp = head.getRight();
}
return true;
} //删除链表中从head开始的第一个element数据
public T remove(T element) {
if(isEmpty() || element == null) return null;
//从表中第一个元素开始比较
Node<T> temp = head.getRight();
int k=0;
while(temp != head) {
if(element.equals(temp.getData())) {
remove(k);
return element;
}else {
temp = temp.getRight();
k++;
}
}
if(k == (Length()-1)) {
System.out.println("该链表中没有该数据");
}
return element;
} //修改下标index处的数据,并将原始数据返回
public T setElement(int index,T element) {
if(index < 0 || index >= Length()) return null;
Node<T> temp = head;
int k = 0;
while(k < index && temp.getRight() != head) {
k++;
temp = temp.getRight();
}
T tempEle = temp.getData();
temp.setData(element);
return tempEle;
} //重写父类toString方法,实际是给list做遍历后将数据打印出来
public String toString() {
StringBuffer sb = new StringBuffer();
/*通过for循环遍历双向循环链表
int length = Length();
sb.append("[ ");
for(int i = 0; i < length; i++) {
sb.append(getElement(i)+" ");
}
sb.append("]");
*/
//从表头开始遍历双向循环链表
sb.append("[ ");
Node<T> node = head;
while(node.getRight() != head) {
sb.append(node.getRight().getData()+" ");
node = node.getRight();
}
sb.append("]");
return sb.toString();
} }

测试类

 package list;

 //************************************************
//*双向循环链表-java实现(画图分析会容易理解得多)
//************************************************ public class TestDoubleLinkedList {
public static void main(String[] args) {
Listable<String> list = new DoubleLinkedList<String>("a");
list.add("b");
list.add("c");
list.addByIndex(3,"e");
list.addByIndex(3,"d");
list.addByIndex(5,"f");
System.out.println(list);
list.addHead("A");
System.out.println(list.Length());
System.out.println(list);
Listable<String> list1 = new DoubleLinkedList<String>("123456");
list.add(list1);
System.out.println(list);
list.remove(100);
list.add("123456");
System.out.println("list="+list);
System.out.println(list1);
list1.removeAll();
System.out.println(list1+" list1 is Empty??"+list1.isEmpty());
list.remove("123456");
System.out.println("list="+list);
System.out.println("remove item="+list.remove("A"));
System.out.println("list="+list);
}
}

完整代码

 package list;

 //************************************************
//*双向循环链表-java实现(画图分析会容易理解得多)
//************************************************ public class TestDoubleLinkedList {
public static void main(String[] args) {
Listable<String> list = new DoubleLinkedList<String>("a");
list.add("b");
list.add("c");
list.addByIndex(3,"e");
list.addByIndex(3,"d");
list.addByIndex(5,"f");
System.out.println(list);
list.addHead("A");
System.out.println(list.Length());
System.out.println(list);
Listable<String> list1 = new DoubleLinkedList<String>("123456");
list.add(list1);
System.out.println(list);
list.remove(100);
list.add("123456");
System.out.println("list="+list);
System.out.println(list1);
list1.removeAll();
System.out.println(list1+" list1 is Empty??"+list1.isEmpty());
list.remove("123456");
System.out.println("list="+list);
System.out.println("remove item="+list.remove("A"));
System.out.println("list="+list);
}
} //结点类
class Node<T> {
private Node<T> left,right;
private T data; Node(T data) {
this(data,null,null);
} Node() {
this(null,null,null);
} Node(T data,Node<T> left,Node<T> right) {
this.data = data;
this.left = left;
this.right = right;
} public T getData() {
return this.data;
} public Node<T> getLeft() {
return this.left;
} public Node<T> getRight() {
return this.right;
} public void setData(T data) {
this.data = data;
} public void setRight(Node<T> right) {
this.right = right;
} public void setLeft(Node<T> left) {
this.left = left;
} public String toString() {
return getData().toString();
}
} //接口实现类
class DoubleLinkedList<T> implements Listable<T> {
public Node<T> head; //建空表,带头结点
DoubleLinkedList() {
this(null);
} //建表,带头结点,表中有一条数据元素
DoubleLinkedList(T element) {
if(element == null) {
head = new Node<T>(element,null,null);
head.setRight(head);
head.setLeft(head);
}else {
Node<T> headRight = new Node<T>(element,null,null);
head = new Node<T>(null,headRight,headRight);
headRight.setLeft(head);
headRight.setRight(head);
}
} //清空当前链表
public void clear() {} //判空表
public boolean isEmpty() {
return head.getRight() == head;
} //表长
public int Length() {
int len = 0;
Node<T> temp = head;
while(temp.getRight() != head) {
len++;
temp = temp.getRight();
}
return len;
} //取下标index处的数据
public T getElement(int index) {
if(index <= 0) {
return head.getRight().getData();
}
int len = Length();
if(index >= len) {
return head.getLeft().getData();
}
T element = null;
if(index > 0 && index < len) {
int k = 0;
Node<T> temp = head;
//此处只能用while不能用if,用错好几次
while(k <= index && temp.getRight() != head) {
k++;
temp = temp.getRight();
}
element = temp.getData();
}
return element;
} //尾添
public boolean add(T element) {
if(element == null) return false;
Node<T> node = new Node<T>(element,head.getLeft(),head);
head.getLeft().setRight(node);
head.setLeft(node);
return true;
} //首添
public boolean addHead(T element) {
if(element == null) return false;
Node<T> node = new Node<T>(element,head,head.getRight());
head.getRight().setLeft(node);
head.setRight(node);
return false;
} //表index处,添加新数据element
public boolean addByIndex(int index, T element) {
if(index <= 0) {
return addHead(element);
}else if(index >= Length()) {
return add(element);
}else {
int k = 0;
Node<T> temp = head;
//此处只能用while不能用if,用错好几次
while(k <= index && temp.getRight() != head) {
k++;
temp = temp.getRight();
}
Node<T> node = new Node<T>(element,temp.getLeft(),temp);
temp.getLeft().setRight(node);
temp.setLeft(node);
}
return true;
} //将参数中的链表添加到当前链表的尾部
public boolean add(Listable<T> slist) {
if(slist.isEmpty() || slist == null) return false;
if(slist instanceof DoubleLinkedList) {
DoubleLinkedList<T> list = (DoubleLinkedList<T>)slist;
//以下操作影响到了添加的slist表,所以需要将slist表重新备份一个
DoubleLinkedList<T> temp = new DoubleLinkedList<T>();
for(int i = 0; i < list.Length(); i++) {
temp.add(list.getElement(i));
}
Node<T> node = temp.head;
Node<T> nodeLeft = node.getLeft();
Node<T> nodeRight = node.getRight();
this.head.getLeft().setRight(node.getRight());
nodeRight.setLeft(this.head.getLeft());
nodeLeft.setRight(this.head);
this.head.setLeft(node.getLeft());
return true;
}else {
return false;
}
} //删除下标Index处的数据
public T remove(int index) {
if(isEmpty()) return null;
if(index < 0) {
index = 0;
}
int len = Length();
if(index >= len) {
//当index大于或等于表长是,默认移走表的最后一个元素,即下标为len-1的数据
index = len-1;
}
T element = null;
if(index >= 0 && index < len) {
Node<T> temp = head;
int k = 0;
while(k <= index && temp.getRight() != head) {
k++;
temp = temp.getRight();
}
element = temp.getData();
temp.getRight().setLeft(temp.getLeft());
temp.getLeft().setRight(temp.getRight());
temp.setRight(null);
temp.setLeft(null);
temp = null;
}
return element;
} //删除当前链表中所有的数据,只剩头结点
public boolean removeAll() {
if(isEmpty()) return false;
Node<T> temp = head.getRight();
while(temp != head) {
head.setRight(temp.getRight());
temp.getRight().setLeft(head);
temp.setLeft(null);
temp.setRight(null);
temp = head.getRight();
}
return true;
} //删除链表中从head开始的第一个element数据
public T remove(T element) {
if(isEmpty() || element == null) return null;
//从表中第一个元素开始比较
Node<T> temp = head.getRight();
int k=0;
while(temp != head) {
if(element.equals(temp.getData())) {
remove(k);
return element;
}else {
temp = temp.getRight();
k++;
}
}
if(k == (Length()-1)) {
System.out.println("该链表中没有该数据");
}
return element;
} //修改下标index处的数据,并将原始数据返回
public T setElement(int index,T element) {
if(index < 0 || index >= Length()) return null;
Node<T> temp = head;
int k = 0;
while(k < index && temp.getRight() != head) {
k++;
temp = temp.getRight();
}
T tempEle = temp.getData();
temp.setData(element);
return tempEle;
} //重写父类toString方法,实际是给list做遍历后将数据打印出来
public String toString() {
StringBuffer sb = new StringBuffer();
/*通过for循环遍历双向循环链表
int length = Length();
sb.append("[ ");
for(int i = 0; i < length; i++) {
sb.append(getElement(i)+" ");
}
sb.append("]");
*/
//从表头开始遍历双向循环链表
sb.append("[ ");
Node<T> node = head;
while(node.getRight() != head) {
sb.append(node.getRight().getData()+" ");
node = node.getRight();
}
sb.append("]");
return sb.toString();
} }

后期会添加两个链表求交集等操作。

java与数据结构(4)---java实现双向循环链表的更多相关文章

  1. java与数据结构(3)---java实现循环链表

    循环链表:将单链表中尾结点的指针由空指针改为指向头结点,就使整个单链表形成一个环,这种首尾相接的单链表称为单链表循环表,即循环链表. 循环链表与单链表最重要的区别是:尾结点的指针,不再是p->n ...

  2. java与数据结构(8)---java实现链队列

    链队列 实际上就是单链表,只是规定了删除在队头进行,添加在队尾进行. 链队列代码结构 package list.queue; public interface Queuable<T>; p ...

  3. java与数据结构(6)---java实现链栈

    栈之链式存储结构链栈 链栈 栈的链式存储结构成为链栈.链栈是没有头结点,头结点就是栈顶指针top. 代码结构 package list; public interface Stackable;公共接口 ...

  4. java与数据结构(2)---java实现静态链表

    结点类 1 //结点类 2 class Node<T> { 3 private T data; 4 private int cursor; 5 6 Node(T data, int cur ...

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

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

  6. 双向循环链表的Java版本实现

    1.单项循环列表 单向循环链表是单链表的另一种形式,其结构特点是链表中最后一个结点的指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个环.和单链表相比,循环单链表的长处是从链尾到链 ...

  7. java实现双向循环链表

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

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

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

  9. 数据结构(java版)学习笔记(四)——线性表之循环链表

    单向循环链表 PS:有阴影的结点是头结点 概念: 最后一个结点的链域值不为NULL,而是指向头结点 特点: 从表中的任意结点出发,都可以找到表中其他结点 循环条件 p==h 双向链表 概念 链表中的每 ...

随机推荐

  1. centos5.5上apache快速安装H264流媒体支持MP4-H264边下边播

    2013年的某一天,客户反馈北京同事做的广告视频下载速度好慢,几MB的视频在手机上要下载接近一分钟才能开始播放. 我分析后发现两点:1)托管的服务器没支持流媒体:2)广告视频MP4并非流媒体格式. 对 ...

  2. 在Github上面搭建Hexo博客(一):部署到Github

    什么是Hexo Hexo是一个基于Node.js的静态博客程序,可以方便的生成静态网页托管在Github和Heroku上.并且有很多人为其制作了很多优秀的主题(theme),你可以根据自己的喜好进行设 ...

  3. eclipse-android-activity_main/fragment_main文件处理

    android新建工程后,在res/layout/下有两个文件,之前用studio的时候貌似没有,只有一个文件,然后再测试Activity切换的时候,一直在纠结这个问题,下面是解决方法: 1)将fra ...

  4. hdu 2689

    hdu 2689 超级大水题....两种代码都过了,开始以为n^2会tle,后来竟然过了...汗 注意下cin写在while里面,就可以了 #include <iostream> usin ...

  5. PHP 开发工具【2】

    关于PHP的开发工具其实网站上可以搜索到非常多,对于初学者来说,太多的选择反而不知道怎么去选. 本文是基于window平台上,针对PHP初学者定制了一套非常好用的开发工具. PHP开发工具其实包括以下 ...

  6. Javascript 常用函数【3】

    jquery选中radio //如果之前有选中的,则把选中radio取消掉 $("#tj_cat .pro_category").each(function() { if ($(t ...

  7. 武汉科技大学ACM:1002: 华科版C语言程序设计教程(第二版)例题6.6

    Problem Description 明天就要英语考试了,小明明正在挑灯夜 战背单词.小明明发现单词很难背,背一个忘一个.经过仔细研究,小明明发现单词难背的原因是因为某个字符的出现,破坏了整个单词的 ...

  8. java学习——正则表达式

    本文内容来源于  历经5年锤练--史上最适合初学者入门的Java基础视频 例:要求QQ号长度为5~15位,不能以0开头 String qq="123456"; String reg ...

  9. POJ 3254 状压DP

    题目大意: 一个农民有一片n行m列 的农场   n和m 范围[1,12]  对于每一块土地 ,1代表可以种地,0代表不能种. 因为农夫要种草喂牛,牛吃草不能挨着,所以农夫种菜的每一块都不能有公共边. ...

  10. jq仿虾米网flash效果

    这是很久以前写的一个效果了,之前虾米音乐网首页的一个flash效果,最初觉得这flash效果也可以完全用jq来写,于是空余时间就写了下当作练习吧,现在就拿出来跟大家分享下其中的实现原理! 先上最终效果 ...