記一次安裝Redis 6.0.9單例項過程
阿新 • • 發佈:2021-02-08
連結串列由結點組成,每個結點除了儲存自身的資料,還需要有指向其他結點的指標。與陣列相比,連結串列在物理儲存上是不連續的,不能通過下標進行隨機訪問來獲取元素。但是連結串列可以很容易的通過調整指標的指向實現增加和刪除結點。
按指標的指向,連結串列分為:
- 單向連結串列
- 雙向連結串列
單向連結串列
單向連結串列的結點只有一個指向下一個結點的指標。
先建立一個結點物件,包含一個指標屬性next:
public class Node {
private int data;
private Node next;
public Node() {
}
public Node(int data) {
this.data = data;
}
public Node(Node next) {
this.next = next;
}
public Node(int data, Node next) {
this.data = data;
this.next = next;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"data=" + data +
'}';
}
}
將對單向連結串列的常用操作封裝到類中:
public class SingleLinkedList {
/**
* 遍歷單向連結串列
* @param head 頭結點
*/
public void list(Node head) {
if (head == null || head.getNext() == null) {
System.out.println("the List is empty");
return;
}
Node temp = head.getNext();
while (true) {
if (temp == null) {
break;
}
System.out.println(temp);
temp = temp.getNext();
}
}
/**
* 獲取單向連結串列長度(結點個數),不統計頭結點
* @param head 頭結點
* @return 返回連結串列長度(結點個數)
*/
public int getLength(Node head) {
if (head == null || head.getNext() == null) {
return 0;
}
Node temp = head.getNext();
int length = 0;
while (temp != null) {
length++;
temp = temp.getNext();
}
return length;
}
/**
* 新增結點到單向連結串列的最後
* 1.找到當前單向連結串列的最後結點
* 2.將最後結點的next指向新結點
* @param head 頭結點
* @param node
*/
public boolean add(Node head, Node node) {
if (head == null || node == null) {
return false;
}
Node temp = head;
while (true) {
if (temp.getNext() == null) {
break;
}
temp = temp.getNext();
}
temp.setNext(node);
return true;
}
/**
* 新增結點到指定結點後面
* @param node 指定的結點
* @param insertNode 新增的結點
*/
public boolean insert(Node node, Node insertNode) {
if (node == null || insertNode == null) {
return false;
}
if (node.getNext() == null) {
node.setNext(insertNode);
return true;
}
insertNode.setNext(node.getNext());
node.setNext(insertNode);
return true;
}
/**
* 刪除指定結點,需要找到指定結點的前一個結點
* @param deleteNode 刪除的結點
*/
public boolean delete(Node head, Node deleteNode) {
if (head == null || deleteNode == null || head == deleteNode) {
return false;
}
Node temp = head;
while (true) {
if (temp.getNext() == null) {
return false;
}
if (temp.getNext() == deleteNode) {
break;
}
temp = temp.getNext();
}
temp.setNext(temp.getNext().getNext());
return true;
}
}
進行測試:
public static void main(String[] args) {
Node head = new Node(0);
SingleLinkedList singleLinkedList = new SingleLinkedList();
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
Node node4 = new Node(4);
System.out.println("===新增結點到最後===");
singleLinkedList.add(head,node1);
singleLinkedList.add(head,node2);
singleLinkedList.add(head,node3);
singleLinkedList.add(head,node4);
System.out.println("連結串列結點為:");
singleLinkedList.list(head);
System.out.println("連結串列長度為:");
System.out.println(singleLinkedList.getLength(head));
System.out.println("===新增結點到指定結點後面===");
Node node5 = new Node(5);
singleLinkedList.insert(node2,node5);
System.out.println("連結串列結點為:");
singleLinkedList.list(head);
System.out.println("連結串列長度為:");
System.out.println(singleLinkedList.getLength(head));
System.out.println("===刪除指定結點===");
singleLinkedList.delete(head,node5);
System.out.println("連結串列結點為:");
singleLinkedList.list(head);
System.out.println("連結串列長度為:");
System.out.println(singleLinkedList.getLength(head));
}
輸出結果為:
===新增結點到最後===
連結串列結點為:
Node{data=1}
Node{data=2}
Node{data=3}
Node{data=4}
連結串列長度為:
4
===新增結點到指定結點後面===
連結串列結點為:
Node{data=1}
Node{data=2}
Node{data=5}
Node{data=3}
Node{data=4}
連結串列長度為:
5
===刪除指定結點===
連結串列結點為:
Node{data=1}
Node{data=2}
Node{data=3}
Node{data=4}
連結串列長度為:
4
反轉單向連結串列
指定一個新的頭結點,將每一個處理的結點都放在新的頭結點之後。
/**
* 反轉單向連結串列
* @param head
* @return
*/
public Node reverse(Node head) {
if (head == null || head.getNext() == null) {
return head;
}
// 指定一個新的頭結點
Node newHead = new Node(0);
// 指定當前處理的結點
Node curr = head.getNext();
// 指定當前處理結點的下一結點
Node next = null;
while (curr != null) {
// 第一步:獲取反轉前當前結點的下一結點
next = curr.getNext();
// 第二步:指定當前結點的下一結點為新的頭結點的下一結點
curr.setNext(newHead.getNext());
// 第三步:指定新的頭結點的下一結點為當前處理的結點
newHead.setNext(curr);
// 繼續處理後一個結點
curr = next;
}
// 指定原頭結點的下一結點為新頭結點的下一結點
head.setNext(newHead.getNext());
return head;
}
第一個結點處理示意圖:
第二個結點處理示意圖:
前面的迴圈遍歷都沒有考慮單向列表成環的情況,如果有環的話,就會導致無限迴圈,可以通過快慢指標來檢查環:
/**
* 檢測環
* @param head 頭結點
* @return
*/
public boolean checkCircle(Node head) {
if (head == null) {
return false;
}
Node fast = head.getNext();
Node slow = head;
while (fast != null && fast.getNext() != null) {
fast = fast.getNext().getNext();
slow = slow.getNext();
if (slow == fast) {
return true;
}
}
return false;
}
雙向連結串列
雙向連結串列的結點有兩個指標,分別指向上一個結點和下一個結點。
先建立一個結點物件,包含兩指標屬性pre和next:
public class DoubleNode {
private int data;
private DoubleNode pre;
private DoubleNode next;
public DoubleNode() {
}
public DoubleNode(int data) {
this.data = data;
}
public DoubleNode(DoubleNode pre, DoubleNode next) {
this.pre = pre;
this.next = next;
}
public DoubleNode(int data, DoubleNode pre, DoubleNode next) {
this.data = data;
this.pre = pre;
this.next = next;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public DoubleNode getPre() {
return pre;
}
public void setPre(DoubleNode pre) {
this.pre = pre;
}
public DoubleNode getNext() {
return next;
}
public void setNext(DoubleNode next) {
this.next = next;
}
@Override
public String toString() {
return "DoubleNode{" +
"data=" + data +
'}';
}
}
將對雙向連結串列的常用操作封裝到類中:
public class DoubleLinkedList {
/**
* 遍歷雙向連結串列
* @param head 頭結點
*/
public void list(DoubleNode head) {
if (head.getNext() == null) {
System.out.println("the List is empty");
return;
}
DoubleNode temp = head.getNext();
while (true) {
if (temp == null) {
break;
}
System.out.println(temp);
temp = temp.getNext();
}
}
/**
* 獲取雙向連結串列長度(結點個數),不統計頭結點
* @param head 頭結點
* @return 返回連結串列長度(結點個數)
*/
public int getLength(DoubleNode head) {
if (head == null || head.getNext() == null) {
return 0;
}
DoubleNode temp = head.getNext();
int length = 0;
while (temp != null) {
length++;
temp = temp.getNext();
}
return length;
}
/**
* 新增結點到雙向連結串列的最後
* 1.找到當前雙向連結串列的最後結點
* 2.將最後結點的next指向新結點
* 3.將新結點的pre指向前一結點
* @param head 頭結點
* @param node 增加的結點
*/
public void add(DoubleNode head, DoubleNode node) {
DoubleNode temp = head;
while (true) {
if (temp.getNext() == null) {
break;
}
temp = temp.getNext();
}
temp.setNext(node);
node.setPre(temp);
}
/**
* 新增結點到指定結點後面
* @param node 指定的結點
* @param insertNode 新增的結點
*/
public boolean insertAfter(DoubleNode node, DoubleNode insertNode) {
if (node == null || insertNode == null) {
return false;
}
if (node.getNext() == null) {
node.setNext(insertNode);
insertNode.setPre(node);
return true;
}
insertNode.setPre(node);
insertNode.setNext(node.getNext());
node.getNext().setPre(insertNode);
node.setNext(insertNode);
return true;
}
/**
* 新增結點到指定結點前面
* @param node 指定的結點
* @param insertNode 新增的結點
*/
public boolean insertBefore(DoubleNode node, DoubleNode insertNode) {
if (node == null || insertNode == null) {
return false;
}
if (node.getPre() == null) {
insertNode.setNext(node);
node.setPre(insertNode);
return true;
}
insertNode.setPre(node.getPre());
insertNode.setNext(node);
node.getPre().setNext(insertNode);
node.setPre(insertNode);
return true;
}
/**
* 刪除指定結點
* @param deleteNode 刪除的結點
*/
public boolean delete(DoubleNode deleteNode) {
if (deleteNode == null) {
return false;
}
if (deleteNode.getPre() != null){
deleteNode.getPre().setNext(deleteNode.getNext());
}
if (deleteNode.getNext() != null) {
deleteNode.getNext().setPre(deleteNode.getPre());
}
return true;
}
/**
* 檢測環
* @param head 頭結點
* @return
*/
public boolean checkCircle(DoubleNode head) {
if (head == null) {
return false;
}
DoubleNode fast = head.getNext();
DoubleNode slow = head;
while (fast != null && fast.getNext() != null) {
fast = fast.getNext().getNext();
slow = slow.getNext();
if (slow == fast) {
return true;
}
}
return false;
}
}
進行測試:
public static void main(String[] args) {
DoubleNode head = new DoubleNode(0);
DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
DoubleNode node1 = new DoubleNode(1);
DoubleNode node2 = new DoubleNode(2);
DoubleNode node3 = new DoubleNode(3);
DoubleNode node4 = new DoubleNode(4);
System.out.println("===新增結點到最後===");
doubleLinkedList.add(head,node1);
doubleLinkedList.add(head,node2);
doubleLinkedList.add(head,node3);
doubleLinkedList.add(head,node4);
System.out.println("連結串列結點為:");
doubleLinkedList.list(head);
System.out.println("連結串列長度為:");
System.out.println(doubleLinkedList.getLength(head));
System.out.println("===新增結點到指定結點後面===");
DoubleNode node5 = new DoubleNode(5);
doubleLinkedList.insertAfter(node2,node5);
System.out.println("連結串列結點為:");
doubleLinkedList.list(head);
System.out.println("連結串列長度為:");
System.out.println("===新增結點到指定結點前面===");
DoubleNode node6 = new DoubleNode(6);
doubleLinkedList.insertBefore(node2,node6);
System.out.println("連結串列結點為:");
doubleLinkedList.list(head);
System.out.println("連結串列長度為:");
System.out.println(doubleLinkedList.getLength(head));
System.out.println("===刪除指定結點===");
doubleLinkedList.delete(node5);
System.out.println("連結串列結點為:");
doubleLinkedList.list(head);
System.out.println("連結串列長度為:");
System.out.println(doubleLinkedList.getLength(head));
}
輸出結果為:
===新增結點到最後===
連結串列結點為:
DoubleNode{data=1}
DoubleNode{data=2}
DoubleNode{data=3}
DoubleNode{data=4}
連結串列長度為:
4
===新增結點到指定結點後面===
連結串列結點為:
DoubleNode{data=1}
DoubleNode{data=2}
DoubleNode{data=5}
DoubleNode{data=3}
DoubleNode{data=4}
連結串列長度為:
===新增結點到指定結點前面===
連結串列結點為:
DoubleNode{data=1}
DoubleNode{data=6}
DoubleNode{data=2}
DoubleNode{data=5}
DoubleNode{data=3}
DoubleNode{data=4}
連結串列長度為:
6
===刪除指定結點===
連結串列結點為:
DoubleNode{data=1}
DoubleNode{data=6}
DoubleNode{data=2}
DoubleNode{data=3}
DoubleNode{data=4}
連結串列長度為:
5
歡迎關注我的公眾號,一起學習。