資料結構(java)——單鏈表、雙端連結串列和雙向連結串列
阿新 • • 發佈:2019-02-03
單鏈表
連結串列大家都很熟悉,連結串列是由若干個節點串起來的一個結構。類似於火車一樣,擁有一個頭結點(火車頭)之後掛著一個個的節點,每個節點後面跟上另一個節點。每個節點分為兩個域,一個數據域,用來存放這個節點的資料,一個是節點域,用來存放下一個節點。
所以對於單鏈表,用java實現我們首先建立節點類。
Node類:
//聯結點,相當於是車廂 public class Node { //資料域 public long data; //節點域 public Node next; //預設構造方法 public Node(long value) { this.data = value; } //顯示方法 public void display() { System.out.print(data + " "); } }
再實現一些連結串列的基本操作。
LinkList類:
//連結串列,相當於火車 public class LinkList { //車頭,頭結點 private Node first; public LinkList() { first = null; } //插入節點,在頭結點之後插入 public void insertFirst(long value) { Node aNode = new Node(value); aNode.next = first; first = aNode; } //刪除頭節點 public Node deleteFirst() { Node tmp = first.next; first = tmp; return tmp; } //顯示方法 public void display() { Node now = first; while(now != null) { now.display(); now = now.next; } System.out.println(); } //查詢方法 public Node find(long value) { Node now = first; while(now.data != value) { if(now.next == null) { return null; } now = now.next; } return now; } //根據數值刪除 public Node delete(long value) { Node now = first; Node before = first; while(now.data != value) { if(now.next == null) { return null; } before = now; now = now.next; } if(now == first) { first = first.next; } else { before.next = now.next; } return now; } }
對上面一些基礎的方法測試:
public class Test { public static void main(String[] args) { LinkList ll = new LinkList(); ll.insertFirst(1); ll.insertFirst(2); ll.insertFirst(3); ll.insertFirst(4); ll.insertFirst(5); ll.display(); // // ll.deleteFirst(); // ll.display(); // ll.find(2).display(); // Node node = ll.delete(2); // ll.display(); } }
雙端連結串列
雙端連結串列相比於單鏈表,其實就是加入了一個尾節點來標識表尾
Node類:
//聯結點,相當於是車廂
public class Node {
//資料域
public long data;
//節點域(後)
public Node next;
//預設構造方法
public Node(long value) {
this.data = value;
}
//顯示方法
public void display() {
System.out.print(data + " ");
}
}
相比於單鏈表,雙端連結串列在插入和刪除等操作時進行了一點小的修改,體現在吧last移動的處理上
FirstLastLinkList類:
//雙端連結串列
public class FirstLastLinkList {
//車頭,頭結點
private Node first;
//尾節點
private Node last;
public FirstLastLinkList() {
first = null;
last = null;
}
//插入節點,在頭結點之後插入
public void insertFirst(long value) {
Node aNode = new Node(value);
if (isEmpty()) {
last = aNode;
}
aNode.next = first;
first = aNode;
}
//尾節點插入
public void insertLast(long value) {
Node aNode = new Node(value);
if (isEmpty()) {
first = aNode;
}
else {
last.next = aNode;
}
last = aNode;
}
//刪除頭節點
public Node deleteFirst() {
Node tmp = first;
if (first.next == null) {
last = null;
}
first = tmp.next;
return tmp;
}
//顯示方法
public void display() {
Node now = first;
while(now != null) {
now.display();
now = now.next;
}
System.out.println();
}
//查詢方法
public Node find(long value) {
Node now = first;
while(now.data != value) {
if(now.next == null) {
return null;
}
now = now.next;
}
return now;
}
//根據數值刪除
public Node delete(long value) {
Node now = first;
Node before = first;
while(now.data != value) {
if(now.next == null) {
return null;
}
before = now;
now = now.next;
}
if(now == first) {
first = first.next;
}
else {
before.next = now.next;
}
return now;
}
//判斷是否為空
public boolean isEmpty() {
return first == null;
}
}
針對雙端連結串列的一點測試(大家可以自己使用測測):
public class Test {
public static void main(String[] args) {
// TODO 自動生成的方法存根
FirstLastLinkList f1 = new FirstLastLinkList();
// f1.insertFirst(34);
// f1.insertFirst(56);
// f1.insertFirst(67);
// f1.display();
//
// f1.deleteFirst();
// f1.deleteFirst();
// f1.display();
f1.insertLast(56);
f1.insertLast(90);
f1.insertLast(12);
f1.display();
// f1.delete(12);
// f1.display();
while (!f1.isEmpty()) {
f1.deleteFirst();
f1.display();
}
}
}
雙向連結串列
為了解決尾刪這個問題,引入雙向連結串列,在單鏈表和雙端連結串列中,如果要進行尾部刪除,就要吧表遍歷一遍,耗時間耗空間。雙向連結串列的每個節點分為3個域,一個數據域,另外兩個節點域,既儲存前面的節點的資訊,也儲存後面的節點的資訊。可以理解為有2個指標,既有next後指標,又有previous前指標。
Node類:
//聯結點,相當於是車廂
public class Node {
//資料域
public long data;
//節點域(後)
public Node next;
//節點域(前)
public Node previous;
//預設構造方法
public Node(long value) {
this.data = value;
}
//顯示方法
public void display() {
System.out.print(data + " ");
}
}
DoubleLinkList類:
//雙向連結串列
public class DoubleLinkList {
//車頭,頭結點
private Node first;
//尾節點
private Node last;
public DoubleLinkList() {
first = null;
last = null;
}
//插入節點,在頭結點之後插入
public void insertFirst(long value) {
Node aNode = new Node(value);
//為空,設定尾節點為新增加的節點
if (isEmpty()) {
last = aNode;
}
//連結串列不為空的時候,把插入前第一個節點的previous指向新節點
else {
first.previous = aNode;
}
aNode.next = first;
first = aNode;
}
//尾節點插入
public void insertLast(long value) {
Node aNode = new Node(value);
if (isEmpty()) {
first = aNode;
}
else {
last.next = aNode;
aNode.previous = last;
}
last = aNode;
}
//刪除頭節點
public Node deleteFirst() {
Node tmp = first;
if (first.next == null) {
last = null;
}
else {
//這裡因為存在雙指標,所以需要吧後面節點的指向前面節點的那個指標置空
first.next.previous = null;
}
first = tmp.next;
return tmp;
}
//刪除尾節點
public Node deleteLast() {
Node tmp = last;
if (first.next == null) {
first = null;
}
else {
//意思同上
last.previous.next = null;
}
last = last.previous;
return last;
}
//顯示方法
public void display() {
Node now = first;
while(now != null) {
now.display();
now = now.next;
}
System.out.println();
}
//查詢方法
public Node find(long value) {
Node now = first;
while(now.data != value) {
if(now.next == null) {
return null;
}
now = now.next;
}
return now;
}
//根據數值刪除
public Node delete(long value) {
Node now = first;
while(now.data != value) {
if(now.next == null) {
return null;
}
now = now.next;
}
if(now == first) {
first = first.next;
}
else {
now.previous.next = now.next;
}
return now;
}
//判斷是否為空
public boolean isEmpty() {
return first == null;
}
}
對雙向連結串列的基本功能進行一些測試:
public class TestDoubleLinkList {
public static void main(String[] args) {
// TODO 自動生成的方法存根
DoubleLinkList dL = new DoubleLinkList();
dL.insertLast(45);
dL.insertLast(56);
dL.insertLast(90);
dL.display();
// dL.deleteLast();
// dL.display();
while(!dL.isEmpty()) {
dL.deleteFirst();
dL.display();
}
}
}