Java實現(xiàn)雙向循環(huán)鏈表
雙向循環(huán)鏈表定義
相比于單鏈表,有兩個指針,next指針指向下一個結點,prior指針指向上一個結點,最后一個結點的next指針指向頭結點,頭結點的prior指針指向最后一個結點
代碼實現(xiàn):
我們對單鏈表的實現(xiàn)加以修改
package algorithm.datastructure.doublelinkedlist; import java.util.NoSuchElementException; /** * 雙向循環(huán)鏈表 * 兩個指針,next指針指向下一個結點,prior指針指向上一個結點,最后一個結點的next指針指向頭結點, * 頭結點的prior指針指向最后一個結點 * */ public class LinkedList { private Node head;//頭節(jié)點 private int size;//鏈表長度 static private class Node{ private int data;//數(shù)據(jù) 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; } //根據(jù)下標獲取元素 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)); } //根據(jù)索引刪除元素 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); } } } //返回鏈表元素個數(shù) public int size(){ return size; } public Boolean isEmpty(){ return size==0; } /**雙向鏈表插入一個結點,要改變的指針如下: * *(1)前一個結點的next指針 *(2)后一個結點的prior指針 *(3)新創(chuàng)建的結點的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; } //數(shù)組下標是否越界 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簡單實現(xiàn)雙向鏈表,更多功能可參考Java集合中的LinkedList實現(xiàn)。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
springboot執(zhí)行延時任務之DelayQueue的使用詳解
DelayQueue是一個無界阻塞隊列,只有在延遲期滿時,才能從中提取元素。這篇文章主要介紹了springboot執(zhí)行延時任務-DelayQueue的使用,需要的朋友可以參考下2019-12-12BeanDefinitionRegistryPostProcessor如何動態(tài)注冊Bean到Spring
這篇文章主要介紹了BeanDefinitionRegistryPostProcessor如何動態(tài)注冊Bean到Spring,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03vscode搭建java開發(fā)環(huán)境的實現(xiàn)步驟
本文主要介紹了vscode搭建java開發(fā)環(huán)境,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-03-03mybatis mybatis-plus-generator+clickhouse自動生成代碼案例詳解
這篇文章主要介紹了mybatis mybatis-plus-generator+clickhouse自動生成代碼案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內容,需要的朋友可以參考下2021-08-08Java使用pdfbox實現(xiàn)給pdf文件加圖片水印
有時候需要給pdf加水印,市面上工具都是收費的要會員,還是自食其力吧;嘗試過 spire.pdf.free 那個超過10頁就不行了!所以本文還是使用了pdfbox,感興趣的可以了解一下2022-11-11