Java实现双向循环链表

双向循环链表定义

相比于单链表,有两个指针,next指针指向下一个结点,prior指针指向上一个结点,最后一个结点的next指针指向头结点,头结点的prior指针指向最后一个结点

代码实现:

我们对单链表的实现加以修改

package algorithm.datastructure.doublelinkedlist;
import java.util.NoSuchElementException;

/*
* 双向循环链表
* 两个指针,next指针指向下一个结点,prior指针指向上一个结点,最后一个结点的next指针指向头结点,
* 头结点的prior指针指向最后一个结点
* */
public class LinkedList {
  private Node head;//头节点
  private int size;//链表长度

  static private class Node{
    private int data;//数据
    private Node next;//下一个结点
    private Node prior;//上一个结点

    public Node(){
    }
    public Node(int data){
      this.data=data;
    }
    private Node(int data,Node next){
      this.data=data;
      this.next=next;
    }

    public Node(Node prior,int data,Node next){
      this.prior=prior;
      this.data=data;
      this.next=next;
    }

  }

  //初始化空链表
  public LinkedList(){
    //head=null;
  }

  //添加元素
  public Boolean add(int element){
    linkLast(element);
    return true;
  }

  //在某个位置之前添加元素
  public Boolean add(int index,Integer element){
    checkPositionIndex(index);
    if (index==size){
      linkLast(element);
    } else {
      linkBefore(element,node(index));
    }

    return true;
  }

  //根据下标获取元素
  public int get(int index){
    checkElementIndex(index);
    return node(index).data;
  }
  //获取第一个元素
  public Integer getFirst(){
    Node f=head;
    if (f==null){
      throw new NoSuchElementException();
    } else {
      return f.data;
    }
  }
  //获取最后一个元素
  public Integer getLast(){
    if (size==0){
      throw new NoSuchElementException();
    }

    return head.prior.data;
  }

  //删除第一个元素
  public Integer removeFirst(){
    Node f=head;
    if (f==null){
      throw new NoSuchElementException();
    } else {
      return unlink(head);
    }
  }

  //删除最后一个元素
  public Integer removeLast(){
    if (size==0){
      throw new NoSuchElementException();
    }
    int index=size-1;
    return unlink(node(index));
  }

  //根据索引删除元素
  public Integer remove(int index){
    checkElementIndex(index);
    return unlink(node(index));
  }

  //销毁链表
  public void destroyList(){
    clearList();
  }
  //将链表置为空表
  public void clearList() {

    for (Node p=head;p!=null;){
      Node next=p.next;//记录下一个结点
      p=null;//删除当前结点
      p=next;//指向下一个结点
    }
    size=0;
    head=null;
  }
  //遍历链表
  public void traverseList(Boolean isReverseVisited){
    if (!isEmpty()){
      if (!isReverseVisited){
        for (Node p=head;p!=head.prior;p=p.next){
          System.out.println(p.data);
        }
        System.out.println(head.prior.data);
      } else {
        for (Node p=head.prior;p!=head;p=p.prior){
          System.out.println(p.data);
        }
        System.out.println(head.data);
      }
    }
  }

  //返回链表元素个数
  public int size(){
    return size;
  }

  public Boolean isEmpty(){
    return size==0;
  }
  /*双向链表插入一个结点,要改变的指针如下:
   *
   *(1)前一个结点的next指针
   *(2)后一个结点的prior指针
   *(3)新创建的结点的prior指针和next指针
   * */
  //尾部添加结点
  private void linkLast(int element){
    if (size==0){//没有结点时
      head=new Node(element);
      head.next=head;
      head.prior=head;
      size++;
    } else {
      //得到最后一个结点
      Node oldTail=head.prior;
      //new新的尾结点 newTail
      //newTail的前一个结点设置为旧的尾结点,
      //newTail的后一个结点指向head
      Node newTail=new Node(oldTail,element,head);
      //head的下一个结点指向newTail
      head.prior=newTail;
      //旧的尾结点的下一个结点指向新的尾结点
      oldTail.next=newTail;
      size++;
    }

  }

  //在某结点之前插入结点
  private void linkBefore(int element,Node node){
    if (node==null){
      linkLast(element);
    } else {
      Node p=head;
      if (node.data==p.data){
        Node q=p.prior;
        Node newNode=new Node(q,element,p);
        q.next=newNode;
        p.prior=newNode;
        size++;
      } else {
        for (p=p.next;p!=head;){
          if (node.data==p.data){
            Node q=p.prior;
            Node newNode=new Node(q,element,p);
            q.next=newNode;
            p.prior=newNode;
            size++;
          }
          p=p.next;
        }

      }

    }

  }
  /*
  * 双向链表删除一个结点:
  * (1)找到该结点
  * (2)找到该结点的前一结点(prior)p和下一结点(next)q
  * (3)p的next指针指向q,q的prior指针指向p
  * (4)如果是删除的是头结点,指明当前头结点
  * */

  //删除结点
  private Integer unlink(Node node){
    Integer deleteNodeData=node.data;
    Node p=null,q=null;
    if (deleteNodeData==head.data){//该结点为头结点
      Node cur=head;
      p=head.prior;
      q=head.next;
      p.next=q;
      q.prior=p;
      head=q;
      cur=null;
      size--;
    } else {
      Node m;
      for (m=head.next;m!=head;){
        if (m.data==deleteNodeData){
          p=m.prior;
          q=m.next;
          p.next=q;
          q.prior=p;
          m=null;
          size--;
          break;
        }
        m=m.next;
      }

    }
    return deleteNodeData;
  }

  //数组下标是否越界
  private Boolean isElementIndex(int index){
    return index>=0&&index<size;
  }
  //插入位置是否越界
  public Boolean isPositionIndex(int index){
    return index>=0&&index<=size;
  }

  //检验下标是否越界,抛出异常
  private void checkElementIndex(int index){
    if(!isElementIndex(index)){
      try {
        throw new IndexOutOfBoundsException("下标越界");
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  //检验插入下标是否越界,抛出异常
  private void checkPositionIndex(int index){
    if(!isPositionIndex(index)){
      try {
        throw new IndexOutOfBoundsException("下标越界");
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  //返回指定位置的元素
  private Node node(int index){
    int nowIndex = 0;
    if(size>0){
      for (Node p=head;p!=head.prior;){
        if (nowIndex==index){
          return p;
        }
        p=p.next;
        nowIndex++;
      }
      if (nowIndex==index){
        return head.prior;
      }
    }
    return null;

  }

  public static void main(String[] args) {

    java.util.LinkedList linkedList0=new java.util.LinkedList();
    linkedList0.add(6);
    linkedList0.remove(0);
    linkedList0.size();
    linkedList0.peek();
    //linkedList0.getFirst();
    linkedList0.clear();

    //测试
    LinkedList linkedList=new LinkedList();
    linkedList.add(2);
    linkedList.add(3);
    linkedList.add(5);
    linkedList.add(7);
    linkedList.add(1);
    linkedList.add(33);

    linkedList.add(4,0);
    linkedList.add(3,1);
    linkedList.add(7,6);
    linkedList.add(0,10);
    linkedList.add(10,11);
    linkedList.remove(0);
    linkedList.remove(0);
    linkedList.remove(0);
    linkedList.remove(1);
    linkedList.remove(4);
    linkedList.remove(5);
    linkedList.remove(0);
//    linkedList.remove(0);
//    linkedList.remove(0);
//    linkedList.remove(0);
   // linkedList.remove(0);
    System.out.println(linkedList.get(0));
    System.out.println(linkedList.get(1));
    System.out.println(linkedList.get(2));
    System.out.println(linkedList.get(3));
    System.out.println(linkedList.getFirst());
    System.out.println(linkedList.getLast());
    linkedList.removeFirst();
    linkedList.removeLast();

    System.out.println("遍历链表");
    linkedList.traverseList(false);
//    System.out.println("逆向遍历链表");
//    linkedList.traverseList(true);
    System.out.println("链表长度");

    System.out.println(linkedList.size());
    linkedList.clearList();

  }
}

总结

以上就是Java简单实现双向链表,更多功能可参考Java集合中的LinkedList实现。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Java采用循环链表结构求解约瑟夫问题

    本文实例讲述了Java采用循环链表结构求解约瑟夫问题的方法.分享给大家供大家参考.具体分析如下: 这是第一次java考试的试题,对于没看过链表的同学来说就不会做,现在回头看看,还真不难. 约瑟夫问题: 有n个人,其编号分别为1,2,3,-,n.这n个人按顺序排成一个圈.现在给定s和d,从第s个人开始从1依次报数,数到d的人出列,然后又从下一个人开始又从1开始依次报数,数到d的人又出列,如此循环,直到最后所有人出列为止.要求定义一个节点类,采用循环链表结构求解约瑟夫问题. 以下java版的答案:

  • java数据结构之实现双向链表的示例

    复制代码 代码如下: /** * 双向链表的实现 * @author Skip * @version 1.0 */public class DoubleNodeList<T> { //节点类 private static class Node<T>{  Node<T> perv;  //前节点  Node<T> next;  //后节点  T data;    //数据 public Node(T t){   this.data = t;  } } priv

  • java双向循环链表的实现代码

    例1: 复制代码 代码如下: package com.xlst.util; import java.util.HashMap;import java.util.Map;import java.util.UUID; /*** 双向循环链表* 完成时间:2012.9.28* 版本1.0* @author xlst**/public class BothwayLoopLinked {/*** 存放链表长度的 map* * 如果简单使用 static int 型的 size 基本类型变量,则只能维护一个

  • java中使用双向链表实现贪吃蛇程序源码分享

    使用双向链表实现贪吃蛇程序 1.链表节点定义: package snake; public class SnakeNode { private int x; private int y; private SnakeNode next; private SnakeNode ahead; public SnakeNode() { } public SnakeNode(int x, int y) { super(); this.x = x; this.y = y; } public int getX(

  • JAVA实现双向链表的增删功能的方法

    JAVA实现双向链表的增删功能,完整代码 package linked; class LinkedTable{ } public class LinkedTableTest { //构造单链表 static Node node1 = new Node("name1"); static Node node2 = new Node("name2"); static Node node3 = new Node("name3"); static Node

  • java实现单链表、双向链表

    本文实例为大家分享了java实现单链表.双向链表的相关代码,供大家参考,具体内容如下 java实现单链表: package code; class Node { Node next; int data; public Node(int data) { this.data=data; } } class LinkList { Node first; //头部 public LinkList() { this.first=null; } public void addNode(Node no) {

  • java 实现双向链表实例详解

    java 实现双向链表实例详解 双向链表是一个基本的数据结构,在Java中LinkedList已经实现了这种结构,不过作为开发者,也要拥有自己显示这种结构的能力.话不多说,上代码:     首先是链表的节点类: /** * 链表节点 * @author Administrator * * @param <T> */ public class ChainNode<T> { private T data; //对象编号 private int dataNo; public ChainN

  • Java实现双向链表(两个版本)

    临近春节,项目都结束了,都等着回家过年了.下面是小编给大家研究数据结构的相关知识,链表算是经常用到的一种数据结构了,现将自己的实现展示如下,欢迎大神赐教. 第一个版本,没有最后一个节点,每次从根节点开始遍历 public class LinkedList<E> { private Node head; public LinkedList() { } public E getFirst(){ if(head==null){ return null; } return head.value; }

  • java基于双向环形链表解决丢手帕问题的方法示例

    本文实例讲述了java基于双向环形链表解决丢手帕问题的方法.分享给大家供大家参考,具体如下: 问题:设编号为1.2--n的几个小孩围坐一圈,约定编号为k(1=<k<=n)的小孩从1开始报数,数到m的那个出列,他的下一位又从1开始报数,数到m的那个人又出列,直到所有人出列为止,由此产生一个出队编号的序列. 我们现在用一个双向环形链表来解这一问题.先来看看下面这幅图: 圆圈代表一个结点,红色的指针指向下一个元素,紫色的指针指向上一个元素.first指针指向第一个元素,表明第一个元素的位置,curs

  • Java语言中链表和双向链表

    链表是一种重要的数据结构,在程序设计中占有很重要的地位.C语言和C++语言中是用指针来实现链表结构的,由于Java语言不提供指针,所以有人认为在Java语言中不能实现链表,其实不然,Java语言比C和C++更容易实现链表结构.Java语言中的对象引用实际上是一个指针(本文中的指针均为概念上的意义,而非语言提供的数据类型),所以我们可以编写这样的类来实现链表中的结点. class Node { Object data; Node next;//指向下一个结点 } 将数据域定义成Object类是因为

  • Java中双向链表详解及实例

    Java中双向链表详解及实例 写在前面: 双向链表是一种对称结构,它克服了单链表上指针单向性的缺点,其中每一个节点即可向前引用,也可向后引用,这样可以更方便的插入.删除数据元素. 由于双向链表需要同时维护两个方向的指针,因此添加节点.删除节点时指针维护成本更大:但双向链表具有两个方向的指针,因此可以向两个方向搜索节点,因此双向链表在搜索节点.删除指定索引处节点时具有较好的性能. Java语言实现双向链表: package com.ietree.basic.datastructure.dublin

  • JAVA 数据结构链表操作循环链表

    JAVA 链表操作:循环链表 主要分析示例: 一.单链表循环链表 二.双链表循环链表 其中单链表节点和双链表节点类和接口ICommOperate<T>与上篇一致,这里不在赘述.参考:JAVA链表操作:单链表和双链表http://www.jb51.net/article/95113.htm 一.单链表循环链表 package LinkListTest; import java.util.HashMap; import java.util.Map; public class SingleCycle

随机推荐