数据结构的组成
对于每种结构的特点及优缺点的那个列表 即使记住了也是非常容易忘的 不如了解功能实现 需要时在分析优缺点
逻辑结构:
线性结构 -> 集合(无逻辑关系 只是放一块)
线性结构(线性表 一对一):队列 栈 一维数组 给予特定特点 方便实现特定功能
非线性结构
树(一对多)
图(多对多)
二位数组
内存结构:
顺序存储: 连续内存存储
链表存储:额外需要存储附近节点的引用
索引存储:额外需要存储索引表,索引表的存储又可以分树/哈希之类
散列存储:额外需要哈希算法
从面向对象的角度,其实是不关系内存结构的,所以虽然一种逻辑结构可以有多种内存表示,比如顺序表/链表 就是线性表+顺序存储/链表存储组成的,但我们常说的数据结构还是指的是逻辑结构
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