線性表概述及單鏈表的Java實現
阿新 • • 發佈:2019-04-27
圖片 git 集合 param com urn verify 需要 不知道
為存儲的數據,指定為泛型;
一、線性表概述
線性表是指一組數據元素之間具有線性關系的元素序列,它表現為:除第一個元素沒有直接前驅元素、最後一個元素沒有直接後繼元素外,其余所有元素都有且僅有一個直接前驅元素和直接後繼元素。
根據存儲結構的不同,線性表可以分為順序存儲和鏈式存儲。
1、順序存儲
順序存儲結構是指用一段地址連續的存儲單元依次存儲線性表的數據元素。
數組就是采用順序存儲結構來存儲的,數組元素的保存和讀取操作的時間復雜度都是O(1)
,而插入和刪除操作的時間復雜度為O(n)
,其優缺點如下:
優點 | 缺點 |
---|---|
快速存取,時間復雜度O(1) | 插入、刪除時,時間復雜度較高為,O(n) |
無需為表示元素之間的邏輯關系而增加額外的存儲空間 | 存儲空間固定,不易擴展,容易造成空間的浪費 |
2、鏈式存儲
鏈式存儲是指數據元素在內存空間中的存儲地址可以是不連續的,元素之間的邏輯關系通過其附帶的指示信息來進行關聯。
單鏈表、雙向鏈表、循環鏈表等都是采用鏈式存儲結構進行存儲的。
對於單鏈表來說,單個結點分為數據域和指針域,指針域附帶的指示信息是下一個結點的存儲地址。
單鏈表元素的讀取、插入和刪除的時間復雜度都是O(n)
,在插入和刪除的操作上,如果我們不知道所要操作結點的指針,那麽相比順序存儲結構的數組沒有優勢,在知道要操作結點的指針的情況下,對於插入或刪除越頻繁,單鏈表的效率優勢就越明顯。
比如插入10個元素,對於數組來說,每插入一個元素都要移動n-1個結點,每次的時間復雜度都是O(n),而對於單鏈表來說,只需要在第一次插入時找到目標位置結點的指針,後續插入都只需要通過移動指針來完成,時間復雜度為O(1)
。
二、單鏈表的Java實現
1、定義單鏈表的存儲結構
public class Node<E> {
E element;
Node next;
Node() {
}
Node(E e) {
this.element = e;
this.next = null;
}
}
一個Node結點包含兩個屬性,E element
Node next
為邏輯上的下一個結點的存儲地址。
2、定義操作接口
public interface Collection<E> {
void add(E e);
void insert( E e, int index);
void delete(int index);
E get(int index);
void modify( E e,int index);
boolean isEmpty();
int size();
}
為集合、列表類操作定義一個包含公有行為的接口。
3、實現單鏈表
單鏈表的插入和刪除操作可以抽象成兩個步驟:
(1)找到目標結點
通過頭節點進行遍歷,直到找到目標結點;
(2)插入或刪除;
插入:
//front為index - 1結點,即要插入位置的前一個結點
node.next = front.next;
front.next = node;
刪除:
//front為index - 1結點,即要刪除位置的前一個結點
node = front.next;
front.next = node.next;
//釋放node結點
node = null;
單鏈表完整實現如下:
public class LinkedList<E> implements Collection<E> {
/**
* 頭指針
*/
private Node<E> head;
/**
* 尾指針
*/
private Node<E> tail;
private int size;
public LinkedList() {
//初始化時創建空的頭指針和尾指針,並指向同一個節點,後續增加元素時,尾指針後移,但頭指針一直不變
head = new Node<E>();
tail = head;
size = 0;
}
@Override
public void add(E e) {
Node node = new Node<E>(e);
//設置尾指針的下一個節點為node
tail.next = node;
//設置node為新的尾指針
tail = node;
//長度+1
size++;
}
@Override
public void insert(E e, int index) {
verifyIndex(index, size);
Node node = new Node<E>(e);
//先遍歷找到index-1結點,然後在index-1結點插入,復雜度O(n)
int i = 0;
//index - 1結點
Node front = head;
while (i < index) {
front = front.next;
i++;
}
node.next = front.next;
front.next = node;
size++;
System.out.println(this.toString());
}
@Override
public void delete(int index) {
verifyIndex(index, size - 1);
//找到index-1節點
int i = 0;
Node front = head;
while (i < index) {
front = front.next;
i++;
}
Node target = front.next;
front.next = target.next;
target = null;
size--;
System.out.println(this.toString());
}
@Override
public E get(int index) {
verifyIndex(index, size - 1);
Node node = head;
int i = 0;
while (i <= index) {
node = node.next;
i++;
}
return (E) node.element;
}
@Override
public void modify(E e, int index) {
verifyIndex(index, size - 1);
Node node = head;
int i = 0;
while (i <= index) {
node = node.next;
i++;
}
node.element = e;
System.out.println(this.toString());
}
@Override
public boolean isEmpty() {
return size <= 0;
}
@Override
public int size() {
return 0;
}
/**
* 判斷操作的索引是否合法,
* @param index
* @param end 右邊界,插入時允許在末尾插入,即end = size
* @return
*/
private void verifyIndex(int index, int end) {
if (index < 0 || index > end) {
throw new IndexOutOfBoundsException("invalid index for LinkedList:" + this.toString());
}
}
@Override
public String toString() {
Node node = head;
StringBuilder stringBuilder = new StringBuilder();
while (node.next != null) {
node = node.next;
stringBuilder.append(node.element + " ");
}
return stringBuilder.toString();
}
}
Github下載地址
線性表概述及單鏈表的Java實現