數據結構的組成
對於每種結構的特點及優缺點的那個列表 即使記住了也是非常容易忘的 不如瞭解功能實現 需要時在分析優缺點
邏輯結構:
線性結構 -> 集合(無邏輯關係 只是放一塊)
線性結構(線性表 一對一):隊列 棧 一維數組 給予特定特點 方便實現特定功能
非線性結構
樹(一對多)
圖(多對多)
二位數組
內存結構:
順序存儲: 連續內存存儲
鏈表存儲:額外需要存儲附近節點的引用
索引存儲:額外需要存儲索引表,索引表的存儲又可以分樹/哈希之類
散列存儲:額外需要哈希算法
從面向對象的角度,其實是不關係內存結構的,所以雖然一種邏輯結構可以有多種內存表示,比如順序表/鏈表 就是線性表+順序存儲/鏈表存儲組成的,但我們常說的數據結構還是指的是邏輯結構
package dataStructure;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 參照linkedlist
* 鏈表 鏈式存儲-- 查找取下標也是需要遍歷 刪除和新增和方便 可查看LinkedList雙向鏈表
* 維護頭結點和鏈表大小 一直往下next
* 哨兵 即守門的 在頭和尾加哨兵 則能減少空值判斷 則整體對外沒有什麼區別
* head.pre = 哨兵
* last.next = 哨兵
*
* Created by EX on 2018/4/12.
*/
public class MyLink implements MyDataStr {
MyNode head;
int size;
public static void main(String[] args) {
MyLink myLink = new MyLink();
myLink.add("ss1");
myLink.add("2");
myLink.add("ss3");
myLink.delete();
myLink.add("ss4");
System.out.println(myLink.find("2"));
System.out.println(myLink.size());
myLink.display();
}
public void add(Object data) {
MyNode newNode = new MyNode(data);
if (head == null) {
head = newNode;
} else {
newNode.next = head;
head = newNode;
}
size++;
}
public Object delete() {
Object data = head.data;
head = head.next;
size--;
return data;
}
public void delete(int i) {
}
public void delete(Object value) {
//刪除指定節點 只需要改變該節點的前後節點的指向
}
public Object get(int i) {
MyNode x = head;
for (int j = 0; j < i; j++) {
x = head.next;
}
return x.data;
}
public MyNode find(Object value) {
//遍歷節點
MyNode current = head;
while (!current.data.equals(value)) {
current = current.next;
if (current == null) {
break;
}
}
return current;
}
public int search(Object value) {
return 0;
}
public void display() {
MyNode x = head;
for (int j = 0; j < size; j++) {
System.out.println(x.data);
x = x.next;
}
}
public int size() {
return size;
}
private class MyNode {
Object data;
MyNode next;
public MyNode(Object data) {
this.data = data;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this,ToStringStyle.JSON_STYLE);
}
}
}
package dataStructure;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 二叉樹 維護root及其左右子樹 以第一個內容爲root 然後根據大小比較後往子樹中添加
* on 2018/4/12.
*/
public class MyTree {
public static void main(String[] args) {
MyTree myTree = new MyTree();
myTree.insert("d");
myTree.insert("a");
myTree.insert("z");
myTree.insert("y");
myTree.insert("b");
myTree.display();
}
Node root;
public Node find(Object data) {
if (root == null) {
return null;
}
Node current = root;
while (current != null) {
if (data.hashCode() > current.data.hashCode()) {
current = root.right;
} else if (data.hashCode() < current.data.hashCode()) {
current = root.left;
} else {
return current;
}
}
return null;
}
public boolean insert(Object data) {
Node newNode = new Node(data);
if (root == null) {
root = newNode;
return true;
}
Node current = root;
Node parentNode = null;
while (current != null) {
parentNode = current;
if (data.hashCode() > current.data.hashCode()) {
/*current = current.right;
if(current == null){
current = newNode;
return true;
}*/
current = current.right;
if (current == null) {//左子節點爲空,直接將新值插入到該節點
parentNode.right = newNode;
return true;
}
} else {
/*Node right = current.left;
if(right == null){
right = newNode;
}else{
current = right;
}
return true;*/
current = current.left;
if (current == null) {//右子節點爲空,直接將新值插入到該節點
parentNode.left = newNode;
return true;
}
}
}
return false;
}
public void display() {
System.out.println("root:" + root);
midDisplay(root);
}
private void midDisplay(Node node) {
if (node != null) {
midDisplay(node.left);
System.out.println(node);
midDisplay(node.right);
}
}
public class Node {
Object data;
Node left;
Node right;
public Node(Object data, Node left, Node right) {
this.data = data;
this.left = left;
this.right = right;
}
public Node(Object data) {
this.data = data;
}
public Node() {
}
@Override
public String toString() {
return (String) data;
}
}
}
hashtable hashCode確定在數組中的位置,equals確定是否需要放入數組下的鏈表
package dataStructure;
import javafx.util.Duration;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.commons.lang3.time.DateUtils;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.util.Hashtable;
/**
* 散列 參照hashTable源碼
* Created by EX-ZHOUXIAOWEI004 on 2018/4/12.
*/
public class MyHashTable<K,V>{
private Entry<?,?>[] table;//存放數據
private transient int count;
private int threshold;//容量
private float loadFactor;//負載因子
private transient int modCount = 0;//元素個數
public static void main(String[] args) {
new MyHashTable<String,String>(10,1);
}
public MyHashTable(int initialCapacity, float loadFactor) {
//參數檢測忽略掉了 直接初始化
this.loadFactor = loadFactor;
// table = new Entry<?,?>[initialCapacity];
threshold = (int)Math.min(initialCapacity * loadFactor, Integer.MAX_VALUE - 8 + 1);
}
public synchronized V put(K key, V value){
Entry<?,?> tab[] = table;//成員變量 賦值給局部變量 成員變量存在堆,局部存在棧 棧的數據操作更快
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;//在table中的下標 或者叫位桶
Entry<K,V> entry = (Entry<K,V>)tab[index];//取到當前位桶的entry 而ertry是一個鏈表
//遍歷這個entry鏈表 確認否存在這個key
for (;entry != null; entry = entry.next){
if (key.equals(entry.key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
//如果不存在這個key
addEntry(hash,key,value,index);
return value;
}
private void addEntry(int hash, K key, V value, int index) {
//確認是否需要擴容
modCount++;
Entry<?,?> tab[] = table;
//取出index下的entry,然後新建一個entry指向原有的entry
Entry<K, V> oldEntry = (Entry<K, V>) tab[index];
Entry<K, V> newEntry = new Entry<K, V>(hash, key, value, oldEntry);//新的entry指向原有的entry
tab[index] = newEntry;
count++;
}
private class Entry<K,V>{
final int hash;
final K key;
V value;
Entry<K,V> next;
public Entry(int hash, K key, V value, Entry<K, V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SIMPLE_STYLE);
}
}
}
java中的數據結構
常用結構
Collection
List- ArrayList 數組實現
- Vector 其實就是數組實現的synchronized 版本
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
LinkedList 雙向鏈表 維持頭和尾 Node first;/Node last
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
Set
HashSet 其內部維護一個HashMap 使用其中key的特性保證唯一性
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
TreeSet 其內部也維護一個TreeMap
Map
HashMap 數組+鏈表(+紅黑樹java8)
TreeMap 紅黑樹
Queen 隊列
ArrayBlockingQueue
LinkedBlockingQueue
線程安全的結構
Collections集合工具也提供內部類SynchronizedList/SynchronizedMap 其本質是利用裝飾者模式,給原方法加上synchronized 悲觀鎖
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
final List<E> list;
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
}
1.5以後的java.util.concurrent併發包下的提供了線程安全的各種list/map,其利用的是CAS樂觀鎖
put時會調用compareAndSwapObject 這是個native方法,而get不會調用
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
Node<K,V> c, Node<K,V> v) {
return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}
[數據結構動態可視化](https://visualgo.net/zh