java數據結構
參考:數組、單鏈表和雙鏈表介紹 以及 雙向鏈表的C/C++/Java實現
主要有以下幾種類型
- 單向鏈表
- 雙端鏈表
- 有序鏈表
- 雙向鏈表
- 有迭代器的鏈表
鏈表的效率
這裏順便談下鏈表和數組相比效率的優越性.在表頭插入和刪除的速度都很快,因爲只需要改變一下引用所以花費O(1)的時間.
平均起來查找,刪除和在指定節點後插入數據都需要搜索一半的鏈結點.需要O(N)次比較和數組一樣.然由於鏈表刪除插入的時候
不需要像數組那種元素的移動.所以效率還是要優於數組.
還有一點就是鏈表的內存可以隨時的擴展內存.而數組的內存是一開始就固定好的.這樣就會導致數組的效率和可用性大大下降.
鏈表劣勢在於隨機訪問,無法像數組那樣直接通過下標找到特定的數據項
java代碼實現
單向鏈表
package cn.zlz.structure;
/**
* 單向鏈表 持有一個首部節點,可以實現棧,後進先出
*/
public class LinkedList<V> {
// 鏈表頭部
private Node first;
// 長度
private int size;
public LinkedList() {
super();
}
// 首部插入新的節點
public Node<V> insertFirst(V value) {
Node<V> node = new Node<V>(value);
// 新節點的next指向老節點
node.setNext(first);
first = node;
// 長度+1
size++;
return node;
}
// 獲取指定位置節點
public Node<V> get(int index) {
if (this.isEmpty()) {
throw new IndexOutOfBoundsException("鏈表爲空");
}
if (index >= size) {
throw new IndexOutOfBoundsException("越界");
}
Node node = first;
while (index-- > 0) {
node = node.getNext();
}
return node;
}
// 刪除指定位置節點
public Node<V> remove(int index) {
if (this.isEmpty()) {
throw new IndexOutOfBoundsException("鏈表爲空");
}
if (index >= size) {
throw new IndexOutOfBoundsException("越界");
}
// 待刪除節點
Node<V> removeNode = null;
// 待刪除節點的上個節點
Node<V> pre = null;
if (index == 0) {
// 沒有上個節點
pre = null;
removeNode = first;
first = removeNode.next;
} else {
pre = this.get(index - 1);
// 已通過長度驗證pre.next存在
removeNode = pre.next;
pre.next = removeNode.next;
}
if (--size <= 0) {
first = null;
}
return removeNode;
}
// 判斷linkList是否爲空
public boolean isEmpty() {
return first == null;
}
// 獲取鏈表長度
public int getSize() {
return size;
}
@Override
public String toString() {
if (first == null) {
return "LinkedList ";
}
return "LinkedList [" + first.toString() + "]";
}
// 節點類
class Node<V> {
private V value;
private Node next;
public Node() {
super();
}
public Node(V value) {
super();
this.value = value;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node [value=" + value + ", next=" + next + "]";
}
}
// 測試
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.insertFirst("a");
linkedList.insertFirst("b");
linkedList.insertFirst("c");
linkedList.insertFirst("d");
linkedList.insertFirst("e");
linkedList.insertFirst("f");
System.out.println(linkedList.toString());
LinkedList<String>.Node<String> node = linkedList.get(2);
System.out.println(node.getValue());
LinkedList<String>.Node<String> removeNode = linkedList.remove(0);
System.out.println(linkedList.toString());
System.out.println(node.getValue());
}
}
雙端單向鏈表
package cn.zlz.structure;
/**
* 雙端單向鏈表 持有一個首部節點引用和尾部節點引用,可以實現隊列,先進先出
*
* 雙端鏈表與傳統鏈表非常相似.只是新增了一個屬性-即對最後一個鏈結點的引用,單向鏈表只能從首部開始操作,雙端鏈表首尾都可以
*/
public class DbPortLinkedList<V> {
// 鏈表頭部
private Node first;
// 鏈表尾部
private Node last;
// 長度
private int size;
public DbPortLinkedList() {
super();
}
// 首部添加新的節點
public Node<V> insertFirst(V value) {
Node<V> node = new Node<V>(value);
// 新節點的next指向老節點
if (this.isEmpty()) {
last = node;
}
node.setNext(first);
first = node;
// 長度+1
size++;
return node;
}
// 尾部添加新的節點
public Node<V> insertLast(V value) {
Node<V> node = new Node<V>(value);
// 新節點的next指向老節點
if (this.isEmpty()) {
first = node;
last = node;
return node;
}
last.setNext(node);
last = node;
// 長度+1
size++;
return node;
}
// 獲取指定位置節點
public Node<V> get(int index) {
if (this.isEmpty()) {
throw new IndexOutOfBoundsException("鏈表爲空");
}
if (index >= size) {
throw new IndexOutOfBoundsException("越界");
}
Node node = first;
while (index-- > 0) {
node = node.getNext();
}
return node;
}
// 刪除指定位置節點
public Node<V> remove(int index) {
if (this.isEmpty()) {
throw new IndexOutOfBoundsException("鏈表爲空");
}
if (index >= size) {
throw new IndexOutOfBoundsException("越界");
}
// 待刪除節點
Node<V> removeNode = null;
// 待刪除節點的上個節點
Node<V> pre = null;
if (index == 0) {
// 沒有上個節點
pre = null;
removeNode = first;
first = removeNode.next;
} else {
pre = this.get(index - 1);
// 已通過長度驗證pre.next存在
removeNode = pre.next;
pre.next = removeNode.next;
}
// 長度-1,並驗證鏈表是否爲空
if (--size <= 0) {
first = null;
last = null;
}
return removeNode;
}
// 判斷linkList是否爲空
public boolean isEmpty() {
return first == null && last == null;
}
// 獲取鏈表長度
public int getSize() {
return size;
}
@Override
public String toString() {
if (first == null) {
return "DbPortLinkedList ";
}
return "DbPortLinkedList [" + first.toString() + "]";
}
// 節點類
class Node<V> {
private V value;
private Node next;
public Node() {
super();
}
public Node(V value) {
super();
this.value = value;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node [value=" + value + ", next=" + next + "]";
}
}
// 測試
public static void main(String[] args) {
DbPortLinkedList<String> dbPortLinkedList = new DbPortLinkedList<String>();
dbPortLinkedList.insertFirst("a");
dbPortLinkedList.insertFirst("b");
dbPortLinkedList.insertLast("c");
dbPortLinkedList.insertFirst("d");
dbPortLinkedList.insertLast("e");
dbPortLinkedList.insertFirst("f");
System.out.println(dbPortLinkedList.toString());
DbPortLinkedList<String>.Node<String> node = dbPortLinkedList.get(2);
System.out.println(node.getValue());
DbPortLinkedList<String>.Node<String> removeNode = dbPortLinkedList.remove(0);
System.out.println(dbPortLinkedList.toString());
System.out.println(removeNode.getValue());
}
}
有序鏈表
package cn.zlz.structure;
/**
* 有序單向鏈表:鏈表中的數據按從小到大排列 持有一個首部節點
* 有序鏈表插入數據效率爲O(N),但查找跟刪除最大數據就是表頭數據效率爲O(1).所以在最小數據存儲頻繁,但又不需要快速插入的時候有序鏈表是個不錯的選擇.
*/
public class SortedLinkedList {
// 鏈表頭部
private Node first;
// 長度
private int size;
public SortedLinkedList() {
super();
}
// 首部插入新的節點
public Node insertFirst(Integer value) {
Node node = new Node(value);
// 查找位置,即找到前面一個節點和後面一個節點
Node pre = null;//插入位置前面節點
Node current = first;//插入位置後面節點
while (current != null && current.getValue()<value) {
pre = current;
current=current.next;
}
//最小的,插在第一個位置
if(pre == null){
first = node;
}else{
pre.next = node;
}
//新插入的節點不管怎麼next都指向當前節點
node.next = current;
// 長度+1
size++;
return node;
}
// 獲取指定位置節點
public Node get(int index) {
if (this.isEmpty()) {
throw new IndexOutOfBoundsException("鏈表爲空");
}
if (index >= size) {
throw new IndexOutOfBoundsException("越界");
}
Node node = first;
while (index-- > 0) {
node = node.getNext();
}
return node;
}
// 刪除指定位置節點
public Node remove(int index) {
if (this.isEmpty()) {
throw new IndexOutOfBoundsException("鏈表爲空");
}
if (index >= size) {
throw new IndexOutOfBoundsException("越界");
}
// 待刪除節點
Node removeNode = null;
// 待刪除節點的上個節點
Node pre = null;
if (index == 0) {
// 沒有上個節點
pre = null;
removeNode = first;
first = removeNode.next;
} else {
pre = this.get(index - 1);
// 已通過長度驗證pre.next存在
removeNode = pre.next;
pre.next = removeNode.next;
}
if (--size <= 0) {
first = null;
}
return removeNode;
}
// 判斷linkList是否爲空
public boolean isEmpty() {
return first == null;
}
// 獲取鏈表長度
public int getSize() {
return size;
}
@Override
public String toString() {
if (first == null) {
return "SortedLinkedList ";
}
return "SortedLinkedList [" + first.toString() + "]";
}
// 節點類
class Node {
private int value;
private Node next;
public Node() {
super();
}
public Node(int value) {
super();
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node [value=" + value + ", next=" + next + "]";
}
}
// 測試
public static void main(String[] args) {
SortedLinkedList sortedLinkedList = new SortedLinkedList();
sortedLinkedList.insertFirst(4);
sortedLinkedList.insertFirst(2);
sortedLinkedList.insertFirst(3);
sortedLinkedList.insertFirst(5);
System.out.println(sortedLinkedList);
}
}
雙向鏈表
package cn.zlz.structure;
/**
* 雙向鏈表,注意畫圖來看
* 注意:雙向鏈表需要初始化一個header頭,但是這個header頭不屬於鏈表的一個元素
*/
public class DbLinkedList<V> {
// 鏈表頭部
private Node header;
// 長度
private int size;
public DbLinkedList() {
super();
//創建表頭
this.header = new Node(null, null, null);
//表頭自循環
this.header.next = this.header;
this.header.pre = this.header;
}
// 首部添加新的節點
public Node<V> insert(int index,V value) {
if (index > size) {
throw new IndexOutOfBoundsException("越界");
}
Node<V> current = null ;
if(size == 0){
current = this.header;
}else{
current = get(index);
}
Node<V> node = new Node<V>(value,current.pre,current);
node.pre.next = node;
node.next.pre = node;
// 長度+1
size++;
return node;
}
public Node<V> insertFirst(int index,V value) {
return this.insert(0, value);
}
public Node<V> insertLast(int index,V value) {
//面向對象
Node<V> node = new Node<V>(value,this.header.pre,this.header);
node.pre.next = node;
node.next.pre = node;
// 長度+1
size++;
return node;
}
// 首部添加新的節點
//注意:雙向鏈表中的元素不包括header
public Node<V> get(int index) {
if (size==0 || index > size) {
throw new IndexOutOfBoundsException("越界");
}
Node<V> node = null;
//如果是後半從後往前找
if(index>(size)/2){
System.out.println("從後往前找");
//header不屬於鏈表,所以z最後一個是插入中的一個。
node = this.header.pre;
int round = size-index;
while (round-->=0) {
node = node.pre;
}
}else{//從前往後找
System.out.println("從前往後找");
//header不屬於鏈表,所以第一個是header的next,插入的時候對0單獨處理了,執行get的時候至少已經插入一條
node = this.header.next;
while (index-->0) {
node = node.next;
}
}
return node;
}
public Node<V> remove(int index){
if (size==0 || index > size-1) {
throw new IndexOutOfBoundsException("越界");
}
Node<V> toDelNode = this.get(index);
toDelNode.pre.next = toDelNode.next;
toDelNode.next.pre = toDelNode.pre;
size--;
return toDelNode;
}
// 獲取鏈表長度
public int getSize() {
return size;
}
// 判斷linkList是否爲空
public boolean isEmpty() {
return size == 0;
}
public Node getHeader() {
return header;
}
public void setHeader(Node header) {
this.header = header;
}
public void setSize(int size) {
this.size = size;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
Node header = this.getHeader();
Node next = header.getNext();
stringBuilder.append(header.getPre().getValue()+":"+header.getValue()+":"+header.getNext().getValue());
while(next!=header){
stringBuilder.append(" ");
stringBuilder.append(next.getPre().getValue()+":"+next.getValue()+":"+next.getNext().getValue());
next = next.next;
}
return stringBuilder.toString();
}
// 節點類
class Node<V> {
private V value;// 值
private Node pre;// 前一個節點
private Node next;// 後一個節點
public Node() {
super();
}
public Node(V value, Node pre, Node next) {
super();
this.value = value;
this.pre = pre;
this.next = next;
}
public Node(V value) {
super();
this.value = value;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
public Node getPre() {
return pre;
}
public void setPre(Node pre) {
this.pre = pre;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
@Override
public String toString() {
return "Node [value=" + value + ", pre=" + pre + ", next=" + next + "]";
}
}
// 測試
public static void main(String[] args) {
DbLinkedList<String> dbLinkedList = new DbLinkedList<String>();
System.out.println(dbLinkedList.toString());
dbLinkedList.insert(0,"a");
System.out.println(dbLinkedList.toString());
dbLinkedList.insert(1,"b");
System.out.println(dbLinkedList.toString());
dbLinkedList.insert(2,"b");
System.out.println(dbLinkedList.toString());
dbLinkedList.insert(1,"c");
System.out.println(dbLinkedList.toString());
dbLinkedList.insert(4,"d");
System.out.println(dbLinkedList.toString());
dbLinkedList.insert(0,"e");
System.out.println(dbLinkedList.toString());
System.out.println(dbLinkedList.get(3).getValue());
// dbLinkedList.insertFirst("f");
System.out.println(dbLinkedList.toString());
}
}