05數據結構和算法(Java描述)~環形單鏈表
本文是上一篇文章的後續,詳情點擊該鏈接
環形鏈表的概述:
環形鏈表依舊採用的是鏈式存儲結構,它的特點就是設置首節點和尾節點相互指向,從而實現 讓整個鏈表形成一個環。在我們實際開發中,常見的環形鏈表有:
環形單鏈表
在單鏈表中,尾節點的指針指向了首節點,從而整個鏈表形成一個環,如下圖所示:
環形雙鏈表
在雙鏈表中,尾節點的指針指向了首節點,首節點的指針指向了尾節點,從而整個鏈表形成一 個環,如下圖所示:
代碼模擬實現
List接口
public interface List {
int size();
void add(Object element);
Object get(int index);
void remove(int index);
void add(int index, Object element);
}
接口實現
package cyclesinglelinkedlist;
/**
* 模擬環形單鏈表的實現
*/
public class CycleSingleLinkedList implements List{
/**
* 用於保存單鏈表中的首節點
*/
private Node headNode;
/**
* 用於保存單鏈表中的尾節點
*/
private Node lastNode;
/**
* 用於保存單鏈表中節點的個數
*/
private int size;
/**
* 獲取單鏈表中節點的個數
* @return
*/
public int size() {
return this.size;
}
/**
* 添加元素
* @param element 需要添加的數據
*/
public void add(Object element) {
// 1.把需要添加的數據封裝成節點對象
Node node = new Node(element);
// 2.處理單鏈表爲空表的情況
if(headNode == null) {
// 2.1把node節點設置爲單鏈表的首節點
headNode = node;
// 2.2把node節點設置爲單鏈表的尾節點
lastNode = node;
}
// 3.處理單鏈表不是空表的情況
else {
// 3.1讓lastNode指向node節點
lastNode.next = node;
// 3.2更新lastNode的值
lastNode = node;
}
// 4.設置lastNode的next值爲headNode
lastNode.next = headNode;
// 5.更新size的值
size++;
}
/**
* 根據序號獲取元素
* @param index 序號
* @return 序號所對應節點的數據值
*/
public Object get(int index) {
// 1.如果序號的取值小於0,則證明是不合法的情況
if(index < 0) {
throw new IndexOutOfBoundsException("序號不合法,index:" + index);
}
// 2.根據序號獲得對應的節點對象
Node node = node(index);
// 3.獲取並返回node節點的數據值
return node.data;
}
/**
* 根據序號刪除元素
* @param index 序號
*/
public void remove(int index) {
// 1.判斷序號是否合法,合法取值範圍:[0, size - 1]
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("序號不合法,index:" + index);
}
// 2.處理刪除節點在開頭的情況
if (index == 0) {
// 2.1獲得刪除節點的後一個節點
Node nextNode = headNode.next;
// 2.2設置headNode的next值爲null
headNode.next = null;
// 2.3設置nextNode爲單鏈表的首節點
headNode = nextNode;
// 2.4設置lastNode的next值爲headNode
lastNode.next = headNode;
}
// 3.處理刪除節點在末尾的情況
else if (index == size - 1) {
// 3.1獲得刪除節點的前一個節點
Node preNode = node(index - 1);
// 3.2設置preNode的next值爲null
preNode.next = null;
// 3.3設置preNode爲單鏈表的尾節點
lastNode = preNode;
// 3.4設置lastNode的next值爲headNode
lastNode.next = headNode;
}
// 4.處理刪除節點在中間的情況
else {
// 4.1獲得index-1所對應的節點對象
Node preNode = node(index - 1);
// 4.2獲得index+1所對應的節點對象
Node nextNode = preNode.next.next;
// 4.3獲得刪除節點並設置next值爲null
preNode.next.next = null;
// 4.4設置preNode的next值爲nextNode
preNode.next = nextNode;
}
// 5.更新size的值
size--;
// 6.判斷size的值是否爲0,如果size的值爲0,則設置headNode和lastNode爲null
if(size == 0) {
headNode = null;
lastNode = null;
}
}
/**
* 根據序號插入元素
* @param index 序號
* @param element 需要插入的數據
*/
public void add(int index, Object element) {
// 1.判斷序號是否合法,合法取值範圍:[0, size]
if(index < 0 || index > size) {
throw new IndexOutOfBoundsException("序號不合法,index:" + index);
}
// 2.把需要添加的數據封裝成節點對象
Node node = new Node(element);
// 3.處理插入節點在開頭位置的情況
if(index == 0) {
// 3.1設置node的next值爲headNode
node.next = headNode;
// 3.2設置node節點爲單鏈表的首節點
headNode = node;
// 3.3設置lastNode的next值爲headNode
lastNode.next = headNode;
}
// 4.處理插入節點在末尾位置的情況
else if(index == size) {
// 4.1設置lastNode的next值爲node
lastNode.next = node;
// 4.2設置node節點爲單鏈表的尾節點
lastNode = node;
// 4.3設置lastNode的next值爲headNode
lastNode.next = headNode;
}
// 5.處理插入節點在中間位置的情況
else {
// 5.1獲得index-1所對應的節點對象
Node preNode = node(index - 1);
// 5.2獲得index所對應的節點對象
Node curNode = preNode.next;
// 5.3設置preNode的next爲node
preNode.next = node;
// 5.4設置node的next爲curNode
node.next = curNode;
}
// 6.更新size的值
size++;
}
/**
* 根據序號獲得對應的節點對象
* @param index 序號
* @return 序號對應的節點對象
*/
private Node node(int index) {
// 0.判斷環形單鏈表是否爲空表
if(headNode == null) {
throw new NullPointerException("環形單鏈表爲空表");
}
// 1.定義一個零時節點,用於輔助單鏈表的遍歷操作
Node tempNode = headNode;
// 2.定義一個循環,用於獲取index對應的節點對象
for(int i = 0; i < index % size; i++) {
// 3.更新tempNode的值
tempNode = tempNode.next;
}
// 4.返回index對應的節點對象
return tempNode;
}
/**
* 節點類
*/
private static class Node {
/**
* 用於保存節點中的數據
*/
private Object data;
/**
* 用於保存指向下一個節點的地址值
*/
private Node next;
/**
* 構造方法
* @param data
*/
public Node(Object data) {
this.data = data;
}
}
}