陣列的兩大缺點:
1。若改變陣列的大小就要建立一個新的陣列,並需要從原陣列複製所有的資料到新的陣列
2。陣列元素在記憶體中依次順序儲存,這意味著向陣列插入一項要移動陣列中的其他元素
因此,我們使用鏈式結構,鏈式結構是儲存資料的結點以及指向其他節點的指標的集合。如此一來,節點可以位於記憶體的任意位置,而且從一個節點到另一個節點的傳遞可以通過在結構中儲存節點間引用來實現。
一。單向連結串列
1。連結串列:
如果一個節點包含指向另一個節點的資料值,那麼多個節點可以連線成一串,只通過一個變數訪問整個節點序列,這樣的節點序列稱為連結串列(linked list)
2。單向連結串列:
如果每個節點僅包含其指向後繼節點的引用,這樣的連結串列稱為單向連結串列。
一個整型單向連結串列的實現:
package com.sohu.blog.denns_zane.list;
/**
* @author dennis
* @Description 整型單向連結串列節點
*/
public class IntSLLNode {
public int info; // 使用者資訊
public IntSLLNode next; // 下一個節點,自引用
/**
* @param info
* @param next
*/
public IntSLLNode( int info, IntSLLNode next) {
this .info = info;
this .next = next;
}
/**
* @param info
*/
public IntSLLNode( int info) {
this (info, null );
}
}
/**
*
*/
package com.sohu.blog.denns_zane.list;
/**
* @author dennis
* desc: 整型單向連結串列
*/
public class IntSLList {
protected IntSLLNode head, tail;
public IntSLList() {
head = tail = null ;
}
public boolean isEmpty() {
return head == null ;
}
/**
* @description 增加新節點,並設定它的next為原head
* @param el
*/
public void addToHead( int el) {
head = new IntSLLNode(el, head);
if (tail == null )
tail = head;
}
/**
* @description 增加新節點,並設定原tail的next為新節點
* @param el
*/
public void addToTail( int el) {
if ( ! isEmpty()) {
tail.next = new IntSLLNode(el);
tail = tail.next;
} else {
head = tail = new IntSLLNode(el);
}
}
public int deleteFromHead() {
if (head == null )
throw new NullPointerException();
int el = head.info;
if (head == tail)
head = tail = null ;
else
head = head.next;
return el;
}
public int deleteFromTail() {
if (head == null )
throw new NullPointerException();
int el = tail.info;
if (head == tail)
head = tail = null ;
else {
IntSLLNode temp;
for (temp = head; temp.next != null && temp.next != tail; temp = temp.next)
tail = temp;
System.out.println(tail.info);
tail.next = null ;
}
return el;
}
public void printAll() {
for (IntSLLNode temp = head; temp != null ; temp = temp.next)
System.out.print(temp.info + " " );
}
public boolean isInList( int el) {
for (IntSLLNode temp = head; temp != null ; temp = temp.next) {
if (temp.info == el)
return true ;
}
return false ;
}
/**
* @param el
*/
public void delete( int el) {
if ( ! isEmpty()) {
if (head == tail && head.info == el)
head = tail = null ;
else if (head.info == el)
head = head.next;
else {
IntSLLNode pred, temp; // pred為找的節點的前一節點,temp即為找到的節點
for (pred = head, temp = head.next; temp != null ; pred = pred.next, temp = temp.next) {
if (temp.info == el) {
pred.next = temp.next; // 前一節點的next設定為當前節點的next
if (temp == tail)
tail = pred;
}
}
}
}
}
}
/**
* @author dennis
* @Description 整型單向連結串列節點
*/
public class IntSLLNode {
public int info; // 使用者資訊
public IntSLLNode next; // 下一個節點,自引用
/**
* @param info
* @param next
*/
public IntSLLNode( int info, IntSLLNode next) {
this .info = info;
this .next = next;
}
/**
* @param info
*/
public IntSLLNode( int info) {
this (info, null );
}
}
/**
*
*/
package com.sohu.blog.denns_zane.list;
/**
* @author dennis
* desc: 整型單向連結串列
*/
public class IntSLList {
protected IntSLLNode head, tail;
public IntSLList() {
head = tail = null ;
}
public boolean isEmpty() {
return head == null ;
}
/**
* @description 增加新節點,並設定它的next為原head
* @param el
*/
public void addToHead( int el) {
head = new IntSLLNode(el, head);
if (tail == null )
tail = head;
}
/**
* @description 增加新節點,並設定原tail的next為新節點
* @param el
*/
public void addToTail( int el) {
if ( ! isEmpty()) {
tail.next = new IntSLLNode(el);
tail = tail.next;
} else {
head = tail = new IntSLLNode(el);
}
}
public int deleteFromHead() {
if (head == null )
throw new NullPointerException();
int el = head.info;
if (head == tail)
head = tail = null ;
else
head = head.next;
return el;
}
public int deleteFromTail() {
if (head == null )
throw new NullPointerException();
int el = tail.info;
if (head == tail)
head = tail = null ;
else {
IntSLLNode temp;
for (temp = head; temp.next != null && temp.next != tail; temp = temp.next)
tail = temp;
System.out.println(tail.info);
tail.next = null ;
}
return el;
}
public void printAll() {
for (IntSLLNode temp = head; temp != null ; temp = temp.next)
System.out.print(temp.info + " " );
}
public boolean isInList( int el) {
for (IntSLLNode temp = head; temp != null ; temp = temp.next) {
if (temp.info == el)
return true ;
}
return false ;
}
/**
* @param el
*/
public void delete( int el) {
if ( ! isEmpty()) {
if (head == tail && head.info == el)
head = tail = null ;
else if (head.info == el)
head = head.next;
else {
IntSLLNode pred, temp; // pred為找的節點的前一節點,temp即為找到的節點
for (pred = head, temp = head.next; temp != null ; pred = pred.next, temp = temp.next) {
if (temp.info == el) {
pred.next = temp.next; // 前一節點的next設定為當前節點的next
if (temp == tail)
tail = pred;
}
}
}
}
}
}
二。雙向連結串列
一個整型雙向連結串列的實現:
/**
*
*/
package com.sohu.blog.denns_zane.list;
/**
* @author dennis desc:雙向連結串列節點
*/
public class IntDLLNode {
public int info;
public IntDLLNode prev, next;
/**
* @param info
* @param prev
* @param next
*/
public IntDLLNode(int info, IntDLLNode next, IntDLLNode prev) {
super();
this.info = info;
this.prev = prev;
this.next = next;
}
public IntDLLNode(int info) {
this(info, null, null);
}
}
/**
*
*/
package com.sohu.blog.denns_zane.list;
/**
* @author dennis
*
*/
public class IntDLList {
private IntDLLNode head, tail;
public IntDLList() {
head = tail = null;
}
public boolean isEmpty() {
return head == null;
}
public void addToHead(int el) {
if (head == null)
head = new IntDLLNode(el);
else {
head = new IntDLLNode(el, head, null);
head.next.prev = head;
}
if (tail == null)
tail = head;
}
public void addToTail(int el) {
if (!isEmpty()) {
tail = new IntDLLNode(el, null, tail);
tail.prev.next = tail;
} else
head = tail = new IntDLLNode(el);
}
public int removeFromTail() {
if (head == null)
throw new NullPointerException();
int el = tail.info;
if (head == tail)
head = tail = null;
else {
tail = tail.prev;
tail.next = null;
}
return el;
}
public int removeFromHead() {
if (head == null)
throw new NullPointerException();
int el = head.info;
if (head == tail)
head = tail = null;
else {
head = head.next;
head.prev = null;
}
return el;
}
public boolean isInList(int el) {
if (head == null)
return false;
IntDLLNode temp;
for (temp = head; temp != null; temp = temp.next) {
if (temp.info == el) {
return true;
}
}
return false;
}
public void delete(int el) {
if (head == null)
throw new NullPointerException();
IntDLLNode temp;
for (temp = head; temp != null; temp = temp.next) {
if (temp.info == el) {
if (temp == head) {
head.next.prev = null;
head = head.next;
} else
temp.prev.next = temp.next;
}
}
}
public void printAll() {
IntDLLNode temp;
for (temp = head; temp != null; temp = temp.next) {
System.out.print(temp.info + " ");
}
System.out.println();
}
}
*
*/
package com.sohu.blog.denns_zane.list;
/**
* @author dennis desc:雙向連結串列節點
*/
public class IntDLLNode {
public int info;
public IntDLLNode prev, next;
/**
* @param info
* @param prev
* @param next
*/
public IntDLLNode(int info, IntDLLNode next, IntDLLNode prev) {
super();
this.info = info;
this.prev = prev;
this.next = next;
}
public IntDLLNode(int info) {
this(info, null, null);
}
}
/**
*
*/
package com.sohu.blog.denns_zane.list;
/**
* @author dennis
*
*/
public class IntDLList {
private IntDLLNode head, tail;
public IntDLList() {
head = tail = null;
}
public boolean isEmpty() {
return head == null;
}
public void addToHead(int el) {
if (head == null)
head = new IntDLLNode(el);
else {
head = new IntDLLNode(el, head, null);
head.next.prev = head;
}
if (tail == null)
tail = head;
}
public void addToTail(int el) {
if (!isEmpty()) {
tail = new IntDLLNode(el, null, tail);
tail.prev.next = tail;
} else
head = tail = new IntDLLNode(el);
}
public int removeFromTail() {
if (head == null)
throw new NullPointerException();
int el = tail.info;
if (head == tail)
head = tail = null;
else {
tail = tail.prev;
tail.next = null;
}
return el;
}
public int removeFromHead() {
if (head == null)
throw new NullPointerException();
int el = head.info;
if (head == tail)
head = tail = null;
else {
head = head.next;
head.prev = null;
}
return el;
}
public boolean isInList(int el) {
if (head == null)
return false;
IntDLLNode temp;
for (temp = head; temp != null; temp = temp.next) {
if (temp.info == el) {
return true;
}
}
return false;
}
public void delete(int el) {
if (head == null)
throw new NullPointerException();
IntDLLNode temp;
for (temp = head; temp != null; temp = temp.next) {
if (temp.info == el) {
if (temp == head) {
head.next.prev = null;
head = head.next;
} else
temp.prev.next = temp.next;
}
}
}
public void printAll() {
IntDLLNode temp;
for (temp = head; temp != null; temp = temp.next) {
System.out.print(temp.info + " ");
}
System.out.println();
}
}
三。跳轉表,迴圈表,自組織表(略)
四。結論
1。需要隨機訪問某元素,陣列更為合適
2。需要動態分配記憶體,經常改變結構,連結串列更為合適
3。相比於連結串列,陣列更為節約空間。畢竟連結串列節點還需要儲存一個或者兩個引用