数据结构
数组
数组是由一组元素(值或变量)组成的数据结构,每个元素有至少一个索引或键来标识
空间占用
Java中数组结构为:
8字节markword
4字节class指针(压缩class指针的情况)
4字节数组大小(决定了数组的最大容量是2^32)
数组元素+对其字节(java中所有对象大小都是8字节的整数倍 , 不足的要用对齐字节补足)
动态数组
Java中自带的动态数组:ArrayList,集合底层其实就是一个动态的、自动扩容的数组。
import java.util.Arrays;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.stream.IntStream;
public class Array implements Iterable<Integer> {
private int size = 0;
private int capacity = 8;
private int[] array = {};
//在数组的最后添加一个元素
public void addLast(int element){
checkAndGrow();
array[size] = element;
size++;
}
//向数组的index索引插入element
public void add(int index , int element){
checkAndGrow();
if(index < size && index >=0){
System.arraycopy(array , index , array , index+1 , size - index);
array[index] = element;
size++;
}
}
//获得数组中位于index的元素
public int get(int index){
return array[index];
}
//遍历
public void foreach(Consumer<Integer> consumer){
for(int i = 0;i<size ;i++){
consumer.accept(array[i]);
}
}
//iterator遍历
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int i = 0;
@Override
public boolean hasNext() {
return i<size;
}
@Override
public Integer next() {
return array[i++];
}
};
}
//流遍历
public IntStream stream(){
return IntStream.of(Arrays.copyOfRange(array , 0 , size));
}
//删除
public int remove(int index){
int removed = array[index];
System.arraycopy(array , index +1 , array , index , size - index);
size--;
return removed;
}
//检查并扩容
public void checkAndGrow(){
if(size == 0){
array = new int[capacity];
}
//扩容
if(size == capacity){
capacity += capacity>>1;
int[] newArray = new int[capacity];
System.arraycopy(array , 0 , newArray , 0 , size);
array = newArray;
}
}
}
二维数组
链表
- 单向链表,每个元素有个指针指向下一个元素
- 双向链表,每个元素有两个指针分别指向上一个和下一个元素
- 循环链表,循环链表尾节点指向头节点head
链表内还有一种特殊的节点称为哨兵节点,也叫做哑元节点,它不存储数据,通常用作头尾,用来简化边界判断
import java.util.Iterator;
import java.util.function.Consumer;
public class SinglyLinkedList implements Iterable<Integer>{//整体
Node head;//头指针
@Override
public Iterator<Integer> iterator() {
return new IntegerIterator();
}
private static class Node{
int value;//值
Node next;//下一个节点指针
public Node(int value , Node next){
this.value = value;
this.next = next;
}
}
//插入头部
public void addFirst(int value){
head = new Node(value , head);
}
//遍历
public void loop(){
Node p = head;
while(p!=null){
System.out.println(p.value);
p = p.next;
}
}
//遍历
public void loop2(Consumer<Integer> consumer){
Node p = head;
while(p!=null){
consumer.accept(p.value);
p = p.next;
}
}
//遍历
private class IntegerIterator implements Iterator<Integer> {
Node p = head;
@Override
public boolean hasNext() { //是否有下一个元素
return p!=null;
}
@Override
public Integer next() { //返回当前值,并指向下一个元素
int v = p.value;
p = p.next;
return v;
}
}
//找到最后一个
private Node findLast(){
if(head == null){
return null;
}
Node p;
for(p = head ; p.next != null;p = p.next){
}
return p;
}
//插入尾部
public void addLast(int value){
Node last = findLast();
if(last == null){
addFirst(value);
}
last.next = new Node(value , null);
}
//找到节点
private Node findNode(int index){
int i = 0;
for(Node p = head;p !=null;p = p.next,i++){
if(i==index){
return p;
}
}
return null;//没找到
}
//得到相应值
public int get(int index){
Node node = findNode(index);
if(node==null){
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , index)
);
}
return node.value;
}
//插入
public void insert(int index , int value){
if(index == 0){
addFirst(value);
return ;
}
Node prev = findNode(index - 1);//上一个节点
if(prev == null){//上一个节点为空
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , index)
);
}
prev.next = new Node(value , prev.next);
}
//移除第一个
public void removeFirst(){
if(head == null){
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , 0)
);
}
head = head.next;
}
//移除
public void remove(int index){
if(index == 0){
removeFirst();
return;
}
Node prev = findNode(index - 1);//上一个节点
if(prev == null){
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , index)
);
}
Node removed = prev.next; // 被删除的节点
if(removed == null){
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , index)
);
}
prev.next = removed.next;
}
}
单向链表-带哨兵
import java.util.Iterator;
import java.util.function.Consumer;
//带哨兵链表
public class SentryLinkedList implements Iterable<Integer>{//整体
private Node head = new Node(666 , null);//头指针
@Override
public Iterator<Integer> iterator() {
return new IntegerIterator();
}
private static class Node{
int value;//值
Node next;//下一个节点指针
public Node(int value , Node next){
this.value = value;
this.next = next;
}
}
//插入头部
public void addFirst(int value){
head = new Node(value , head);
}
//遍历
public void loop(){
Node p = head.next;
while(p!=null){
System.out.println(p.value);
p = p.next;
}
}
//遍历
public void loop2(Consumer<Integer> consumer){
Node p = head.next;
while(p!=null){
consumer.accept(p.value);
p = p.next;
}
}
//遍历
private class IntegerIterator implements Iterator<Integer> {
Node p = head.next;
@Override
public boolean hasNext() { //是否有下一个元素
return p!=null;
}
@Override
public Integer next() { //返回当前值,并指向下一个元素
int v = p.value;
p = p.next;
return v;
}
}
//找到最后一个节点
private Node findLast(){
Node p;
for(p = head ; p.next != null;p = p.next){
}
return p;
}
//插入尾部
public void addLast(int value){
Node last = findLast();
last.next = new Node(value , null);
}
//找到节点
private Node findNode(int index){
int i = 0;
for(Node p = head.next;p !=null;p = p.next,i++){
if(i==index){
return p;
}
}
return null;//没找到
}
//得到相应值
public int get(int index){
Node node = findNode(index);
if(node==null){
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , index)
);
}
return node.value;
}
//插入
public void insert(int index , int value){
if(index == 0){
addFirst(value);
return;
}
Node prev = findNode(index - 1);//上一个节点
if(prev == null){//上一个节点为空
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , index)
);
}
prev.next = new Node(value , prev.next);
}
//移除第一个
public void removeFirst(){
if(head == null){
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , 0)
);
}
head = head.next;
}
//移除
public void remove(int index){
if(index == 0){
removeFirst();
return;
}
Node prev = findNode(index - 1);//上一个节点
if(prev == null){
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , index)
);
}
Node removed = prev.next; // 被删除的节点
if(removed == null){
throw new IllegalArgumentException(
String.format("index [%d] 不合法%n" , index)
);
}
prev.next = removed.next;
}
}
双向链表-带哨兵
import java.util.Iterator;
import java.util.Spliterator;
import java.util.function.Consumer;
public class DoublyLinkedListSentinel implements Iterable<Integer>{
static class Node{
Node prev;//上一个结点指针
int value;//值
Node next;//下一个结点指针
public Node(Node prev , int value , Node next){
this.prev = prev;
this.value = value;
this.next = next;
}
}
private Node head;//头哨兵
private Node tail;//尾哨兵
public DoublyLinkedListSentinel(){
head = new Node(null , 666 , null);
tail = new Node(null , 888 , null);
head.next = tail;
tail.prev = head;
}
private Node findNode(int index){
int i = -1;
for(Node p = head; p != tail ; p = p.next , i++){
if(i == index){
return p;
}
}
return null;
}
public void insert(int index , int value){
Node prev = findNode(index - 1);
if(prev == null){
throw new IllegalArgumentException(
String.valueOf(index)
);
}
Node next = prev.next;
Node inserted = new Node(prev , value , next);
prev.next = inserted;
next.prev = inserted;
}
public void addFirst(int value){
insert(0 , value);
}
public void removeFirst(){
remove(0);
}
public void remove(int index){
Node prev = findNode(index - 1);
if(prev == null){
throw new IllegalArgumentException(
""+index
);
}
Node removed = prev.next;
if(removed == tail){
throw new IllegalArgumentException(
""+index
);
}
Node next = removed.next;
prev.next = next;
next.prev = prev;
}
public void addLast(int value){
Node last = tail.prev;
Node added = new Node(last , value , tail);
last.next = added;
tail.prev = added;
}
public void removeLast(){
Node removed = tail.prev;
Node prev = removed.prev;
prev.next = tail;
tail.prev = prev;
}
@Override
public void forEach(Consumer<? super Integer> action) {
Iterable.super.forEach(action);
}
@Override
public Spliterator<Integer> spliterator() {
return Iterable.super.spliterator();
}
@Override
public Iterator<Integer> iterator() {
return null;
}
}
环形链表-带哨兵
import java.util.Iterator;
public class DoubleLinkedListCircular implements Iterable<Integer>{
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
Node p = sentinel.next;
@Override
public boolean hasNext() {
return p!=sentinel;
}
@Override
public Integer next() {
int value = p.value;
p = p.next;
return value;
}
};
}
private static class Node{
Node prev;
int value;
Node next;
public Node(Node prev , int value , Node next){
this.prev = prev;
this.value = value;
this.next = next;
}
}
private Node sentinel = new Node(null , -1 , null);
public DoubleLinkedListCircular(){
sentinel.prev = sentinel;
sentinel.next = sentinel;
}
public void addFirst(int value){
Node a = sentinel;
Node b = sentinel.next;
Node added = new Node(a , value , b);
a.next = added;
b.prev = added;
}
public void addLast(int value){
Node b = sentinel;
Node a = sentinel.prev;
Node added = new Node(a , value , b);
a.next = added;
b.prev = added;
}
public void removeFirst(){
Node removed = sentinel.next;
if(removed == sentinel){
throw new IllegalArgumentException(
"非法"
);
}
Node a = sentinel;
Node b = removed.next;
a.next = b;
b.prev = a;
}
public void removeLast(){
Node removed = sentinel.prev;
if(removed == sentinel){
throw new IllegalArgumentException(
"非法"
);
}
Node a = removed.prev;
Node b = sentinel;
a.next = b;
b.prev = a;
}
public void removeByValue(int value){
Node removed = findByValue(value);
if(removed == null){
return ;
}
Node a = removed.prev;
Node b = removed.next;
a.next = b;
b.prev = a;
}
private Node findByValue(int value){
Node p = sentinel.next;
while(p != sentinel){
if(p.value == value){
return p;
}
p = p.next;
}
return null;
}
}
队列
概述
计算机科学中,queue是以顺序的方式维护的一组数据集合,在一端添加数据,从另一端移除数据。习惯来说,添加的一端为尾,移除的一端为头。
import java.util.Iterator;
public class LinkedListQueue<E> implements Queue<E> , Iterable<E> {
private static class Node<E>{
E value;
Node<E> next;
public Node(E value , Node<E> next){
this.value = value;
this.next = next;
}
}
private Node<E> head = new Node<>(null , null);
private Node<E> tail = head;
private int size; //节点数
private int capacity; //容量
{
tail.next = head;
}
public LinkedListQueue(int capacity){
this.capacity = capacity;
}
public LinkedListQueue(){
}
@Override
public boolean offer(E value) {
if(isFull()){
return false;
}
Node<E> added = new Node<>(value , head);
tail.next = added;
tail = added;
size++;
return true;
}
@Override
public E poll() {
if(isEmpty()){
return null;
}
Node<E> first = head.next;
head.next = first.next;
size--;
return first.value;
}
@Override
public E peek() {
if(isEmpty()){
return null;
}
return head.next.value;
}
@Override
public boolean isEmpty() {
return head == tail;
}
@Override
public boolean isFull() {
return size == capacity;
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
Node<E> p = head.next;
@Override
public boolean hasNext() {
return p != head;
}
@Override
public E next() {
E value = p.value;
p = p.next;
return value;
}
};
}
}
栈
计算机科学中,stack是一种线性的数据结构,只能在其一段添加数据和移除数据。习惯来说,这一端称之为栈顶,另一端不能操作数据的称之为栈底,如同生活中的一摞书
import java.util.Iterator;
public class ArrayStack<E> implements Stack<E> , Iterable<E> {
private E[] array;
private int top; // 栈顶指针
@SuppressWarnings("all")
public ArrayStack(int capacity){
this.array = (E[]) new Object[capacity];
}
@Override
public boolean push(E value) {
if(isFull()){
return false;
}
array[top++] = value;
return true;
}
@Override
public E pop() {
if(isEmpty()){
return null;
}
E value = array[top - 1];
top--;
return value;
}
@Override
public E peek() {
if(isEmpty()){
return null;
}
return array[top - 1];
}
@Override
public boolean isEmpty() {
return top == 0;
}
@Override
public boolean isFull() {
return top == array.length;
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
int p = top;
@Override
public boolean hasNext() {
return p>0;
}
@Override
public E next() {
E value = array[--p];
return value;
}
};
}
}
双端队列
队列:一端删除(头)一端添加(尾)
栈:一端删除和添加(顶)
双端队列:两端都可以删除、添加
优先级队列:优先级高者先出队
延时队列:根据延时时间确定优先级
并发阻塞队列:队列空或满时不阻塞
并发阻塞队列:队列空时删除阻塞、队列满时添加阻塞
import java.util.Iterator;
public class LinkedListDeque<E> implements Deque<E> , Iterable<E> {
// a added b
@Override
public boolean offerFirst(E e) {
if(isFull()){
return false;
}
Node<E> a = sentinel;
Node<E> b = sentinel.next;
Node<E> added = new Node(a , e , b);
a.next = added;
b.prev = added;
size++;
return false;
}
@Override
public boolean offerLast(E e) {
if(isFull()){
return false;
}
Node<E> a = sentinel.prev;
Node<E> b = sentinel;
Node<E> added = new Node<>(a , e , b);
a.next = added;
b.prev = added;
size++;
return true;
}
@Override
public E pollFirst() {
if(isEmpty()){
return null;
}
Node<E> a = sentinel;
Node<E> removed = sentinel.next;
Node<E> b = removed.next;
a.next = b;
b.prev = a;
size --;
return removed.value;
}
@Override
public E pollLast() {
if(isEmpty()){
return null;
}
Node<E> b = sentinel;
Node<E> removed = sentinel.prev;
Node<E> a = removed.prev;
a.next = b;
b.prev = a;
size--;
return removed.value;
}
@Override
public E peekFirst() {
if(isEmpty()){
return null;
}
return sentinel.next.value;
}
@Override
public E peekLast() {
if(isEmpty()){
return null;
}
return sentinel.prev.value;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean isFull() {
return size == capacity;
}
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
Node<E> p = sentinel.next;
@Override
public boolean hasNext() {
return p != sentinel;
}
@Override
public E next() {
E value = p.value;
p = p.next;
return value;
}
};
}
static class Node<E> {
Node<E> prev;
E value;
Node<E> next;
public Node(Node<E> prev , E value , Node<E> next){
this.prev = prev;
this.value = value;
this.next = next;
}
}
int capacity;
int size;
Node<E> sentinel = new Node<>(null , null , null);
public LinkedListDeque(int capacity){
this.capacity = capacity;
sentinel.next = sentinel;
sentinel.prev = sentinel;
}
}
二叉树
二分搜索树(Binary Search Tree)
平衡二叉树;AVL;红黑树
堆;并查集
线段树;Trie(字典树,前缀树)
二叉树:
-
和链表一样,动态数据结构
-
class Node{ E e; Node left; Node right; }
package BST;
import 栈.LinkedListStack;
import 栈.Stack;
import java.util.LinkedList;
import java.util.Queue;
public class BST<E extends Comparable<E>> {
private class Node{
E e;
Node left , right;
public Node(E e){
this.e = e;
left = null;
right = null;
}
}
private Node root;
private int size;
public BST(){
root = null;
size = 0;
}
public int size(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
public void add(E e){
if(root == null){
root = new Node(e);
size++;
}else {
add(root , e);
}
}
//看二分搜索树中是否包含元素e
public boolean contains(E e){
return contains(root , e);
}
private boolean contains(Node node , E e){
if(node == null){
return false;
}
if(e.compareTo(node.e) == 0){
return true;
}else if(e.compareTo(node.e)<0){
return contains(node.left , e);
}else {
return contains(node.right , e);
}
}
//向以node为根的二分搜索树中插入元素E,递归算法
private Node add(Node node , E e){
if(node == null){
size ++;
return new Node(e);
}
if(e.compareTo(node.e)<0){
node.left = add(node.left , e);
}else if(e.compareTo(node.e)>0){
node.right = add(node.right , e);
}
return node;
}
//前序遍历
public void preOrder(){
preOrder(root);
}
//前序遍历以node为根的二分搜索树,递归算法
private void preOrder(Node node){
if(node == null){
return;
}
System.out.println(node.e);
preOrder(node.left);
preOrder(node.right);
}
//中序遍历以node为根的二分搜索树
public void inOrder(){
inOrder(root);
}
private void inOrder(Node node){
if(node == null) {
return;
}
inOrder(node.left);
System.out.println(node.e);
inOrder(node.right);
}
//后序遍历以node为根的二分搜索树
public void postOrder(){
postOrder();
}
private void postOrder(Node node){
if(node == null){
return;
}
postOrder(node.left);
postOrder(node.right);
System.out.println(node.e);
}
public void preOrderNR(){
Stack<Node> stack = new LinkedListStack<>();
stack.push(root);
while(!stack.isEmpty()){
Node cur = stack.pop();
System.out.println(cur.e);
if(cur.right != null){
stack.push(cur.right);
}
if(cur.left != null){
stack.push(cur.left);
}
}
}
public void levelOrder(){
Queue<Node> q = new LinkedList<>();
q.add(root);
while(!q.isEmpty()){
Node cur = q.remove();
System.out.println(cur.e);
if(cur.left != null){
q.add(cur.left);
}
if(cur.right != null){
q.add(cur.right);
}
}
}
public E minimum(){
if(size == 0){
throw new IllegalArgumentException("BST is empty");
}
return minimum(root).e;
}
private Node minimum(Node node){
if(node.left == null){
return node;
}
return minimum(node.left);
}
public E maximum(){
if(size == 0){
throw new IllegalArgumentException("BST is empty");
}
return minimum(root).e;
}
private Node maximum(Node node){
if(node.right == null){
return node;
}
return minimum(node.right);
}
//从二分搜索树中删除最小值所在的节点,返回最小值
public E removeMin(){
E ret = minimum();
removeMin(root);
return ret;
}
private Node removeMin(Node node){
if(node.left == null){
Node rightNode = node.right;
node.right = null;
size --;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
//从二分搜索树中删除最大值所在的节点,返回最大值
//从二分搜索树中删除最小值所在的节点,返回最小值
public E removeMax(){
E ret = minimum();
removeMax(root);
return ret;
}
private Node removeMax(Node node){
if(node.right == null){
Node leftNode = node.left;
node.left = null;
size --;
return leftNode;
}
node.right = removeMax(node.right);
return node;
}
// 从二分搜索树中删除元素为e的节点
public void remove(E e){
root = remove(root , e);
}
// 删除以node为根的二分搜索树中值为e的节点,递归算法
// 返回删除节点后新的二分搜索树的根
private Node remove(Node node , E e){
if(node == null){
return null;
}
if(e.compareTo(node.e) < 0){
node.left = remove(node.left , e);
return node;
} else if(e.compareTo(node.e) > 0){
node.right = remove(node.right , e);
return node;
} else{ // e == node.e
//待删除节点左子树为空的情况
if(node.left == null){
Node rightNode = node.right;
node.right = null;
size --;
return rightNode;
}
//待删除节点右子树为空的情况
if(node.right == null){
Node leftNode = node.left;
node.left = null;
size --;
return leftNode;
}
// 待删除节点左右子树军部为空的情况
// 找到比带删除节点大的最小节点,即待删除节点右子树的最小节点
// 用这个节点顶替待删除节点的位置
Node successor = minimum(node.right);
successor.right = removeMin(node.right);
successor.left = node.left;
node.left = node.right = null;
return successor;
}
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
generateBSTString(root , 0 , res);
return res.toString();
}
private void generateBSTString(Node node , int depth , StringBuilder res){
if(node == null){
res.append(generateDepthString(depth)+"null\n");
return;
}
res.append(generateDepthString(depth)+node.e+"\n");
generateBSTString(node.left , depth+1 , res);
generateBSTString(node.right , depth +1 , res);
}
private String generateDepthString(int depth){
StringBuilder res = new StringBuilder();
for(int i = 0;i<depth;i++){
res.append("--");
}
return res.toString();
}
}
集合和映射 Set and Map
树映射(TreeMap):
package 映射;
import BST.BST;
public class BSTMap<K extends Comparable<K>,V> implements Map<K , V>{
private class Node{
public K key;
public V value;
public Node left , right;
public Node(K key , V value){
this.key = key;
this.value = value;
left = null;
right = null;
}
}
private Node root;
private int size;
public BSTMap(){
root = null;
size = 0;
}
@Override
public int getSize(){
return size;
}
@Override
public boolean isEmpty(){
return size == 0;
}
@Override
public void add(K key , V value){
root = add(root , key , value);
}
@Override
public V remove(K key) {
Node node = getNode(root , key);
if(node != null){
root = remove(root , key);
return node.value;
}
return null;
}
private Node remove(Node node, K key){
if(node == null){
return null;
}
if(key.compareTo(node.key) < 0){
node.left = remove(node.left , key);
return node;
} else if(key.compareTo(node.key) > 0){
node.right = remove(node.right , key);
return node;
} else{ // e == node.e
//待删除节点左子树为空的情况
if(node.left == null){
Node rightNode = node.right;
node.right = null;
size --;
return rightNode;
}
//待删除节点右子树为空的情况
if(node.right == null){
Node leftNode = node.left;
node.left = null;
size --;
return leftNode;
}
// 待删除节点左右子树军部为空的情况
// 找到比带删除节点大的最小节点,即待删除节点右子树的最小节点
// 用这个节点顶替待删除节点的位置
Node successor = minimum(node.right);
successor.right = removeMin(node.right);
successor.left = node.left;
node.left = node.right = null;
return successor;
}
}
private Node removeMin(Node node){
if(node.left == null){
Node rightNode = node.right;
node.right = null;
size --;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
private Node minimum(Node node){
if(node.left == null){
return node;
}
return minimum(node.left);
}
@Override
public boolean contains(K key) {
return getNode(root , key) != null;
}
@Override
public V get(K key, V newValue) {
Node node = getNode(root , key);
return node == null ? null : node.value;
}
@Override
public void set(K key, V newValue) {
Node node = getNode(root , key);
if(node == null){
throw new IllegalArgumentException(key + "doesn't exist!");
}
node.value = newValue;
}
private Node add(Node node , K key , V value){
if(node == null){
size++;
return new Node(key ,value);
}
if(key.compareTo(node.key)<0){
node.left = add(node.left , key , value);
}else if(key.compareTo(node.key)>0){
node.right = add(node.right , key , value);
}else {
node.value = value;
}
return node;
}
private Node getNode(Node node , K key){
if(node == null){
return null;
}
if(key.compareTo(node.key) == 0){
return node;
}else if(key.compareTo(node.key) < 0){
return getNode(node.left , key);
}else {
return getNode(node.right , key);
}
}
}
优先队列
堆实现:
package 堆;
import 数组.DynamicArray;
public class MaxHeap<E extends Comparable<E>> {
private DynamicArray<E> data;
public MaxHeap(int capacity){
data = new DynamicArray<>(capacity);
}
public MaxHeap(E[] arr){
data = new DynamicArray<>(arr);
for(int i = parent(arr.length -1);i>=0;i--){
siftDown(i);
}
}
public MaxHeap(){
data = new DynamicArray<>();
}
public int size(){
return data.getSize();
}
public boolean isEmpty(){
return data.isEmpty();
}
private int parent(int index){
if(index == 0){
throw new IllegalArgumentException("index -0 doesn't have parent");
}
return (index - 1)/2;
}
private int leftChild(int index){
return index * 2 + 1;
}
private int rightChild(int index){
return index*2 +2;
}
//向堆中添加元素
public void add(E e){
data.addLast(e);
siftUp(data.getSize() - 1);
}
private void siftUp(int k){
while(k >0 && data.get(parent(k)).compareTo(data.get(k)) < 0) {
data.swap(k , parent(k));
k = parent(k);
}
}
public E findMax(){
if(data.getSize()==0){
throw new IllegalArgumentException("Can not findMax when heap is empty!");
}
return data.get(0);
}
public E extractMax(){
E ret = findMax();
data.swap(0 , data.getSize() - 1);
data.remove(data.getSize()-1);
siftDown(0);
return ret;
}
private void siftDown(int k){
while(leftChild(k) < data.getSize()){
int j = leftChild(k);
if(j + 1 < data.getSize() && data.get(j + 1).compareTo(data.get(j)) > 0){
j = rightChild(k);
//data[j] 是 leftChild he rightChild中的最大值
}
if (data.get(k).compareTo(data.get(j)) >= 0){
break;
}
data.swap(k , j);
k = j;
}
}
//去出堆中最大元素,并且替换成元素e
public E replace(E e){
E ret = findMax();
data.set(0 , e);
siftDown(0);
return ret;
}
}
线段树
package 树;
public class SegmentTree<E>{
private E[] tree;
private E[] data;
private Merger<E> merger;
public SegmentTree(E[] arr , Merger<E> merger){
this.merger = merger;
data = (E[])new Object[arr.length];
for(int i = 0;i<arr.length;i++){
data[i] = arr[i];
}
tree = (E[]) new Object[4 * arr.length];
buildSegmentTree(0 , 0 , data.length -1);
}
// 在treeIndex的位置创建表示区间[l....r]的线段树
private void buildSegmentTree(int treeIndex , int l , int r){
if(l == r){
tree[treeIndex] = data[l];
return;
}
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
int mid = l + (r - l) /2;
buildSegmentTree(leftTreeIndex , l , mid);
buildSegmentTree(rightTreeIndex , mid +1 , r);
tree[treeIndex] = merger.merge(tree[leftTreeIndex] , tree[rightTreeIndex]);
}
public int getSize(){
return data.length;
}
public E get(int index){
if(index < 0 || index >= data.length){
throw new IllegalArgumentException("Index is illegal");
}
return data[index];
}
private int leftChild(int index){
return 2*index +1;
}
private int rightChild(int index){
return 2*index +2;
}
public E query(int queryL , int queryR){
if(queryL <0 || queryL >= data.length ||
queryR < 0 || queryR >= data.length || queryL > queryR){
throw new IllegalArgumentException("Index is illegal");
}
return query( 0 , 0 ,data.length -1 , queryL , queryR);
}
//在以treeID为根的线段树中[l...r]的范围里,搜索区间[queryL...queryR]的值
private E query(int treeIndex, int l , int r , int queryL , int queryR){
if(l == queryL && r == queryR){
return tree[treeIndex];
}
int mid = l + (r - l) /2;
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
if(queryL >= mid+1){
return query(rightTreeIndex , mid +1 , r , queryL , queryR);
}else if(queryR <= mid){
return query(leftTreeIndex , l , mid , queryL , queryR);
}
E leftResult = query(leftTreeIndex, l, mid, queryL, mid);
E rightResult = query(rightTreeIndex , mid + 1 , r , mid+1 , queryR);
return merger.merge(leftResult , rightResult);
}
public void set(int index , E e){
if(index < 0 || index >= data.length){
throw new IllegalArgumentException("Index is illegal");
}
data[index] = e;
set(0, 0, data.length-1, index, e);
}
//在以treeIndex为根的线段树中更新index的值为e
private void set(int treeIndex , int l , int r , int index , E e){
if(l == r){
tree[treeIndex] = e;
return;
}
int mid = l + (r - l)/2;
int leftTreeIndex = leftChild(treeIndex);
int rightTreeIndex = rightChild(treeIndex);
if(index >= mid + 1){
set(rightTreeIndex, mid + 1, r, index, e);
}else {
set(leftTreeIndex, l, mid, index, e);
}
tree[treeIndex] = merger.merge(tree[leftTreeIndex], tree[rightTreeIndex]);
}
@Override
public String toString(){
StringBuilder res = new StringBuilder();
res.append('[');
for(int i = 0;i<tree.length;i++){
if(tree[i] !=null){
res.append(tree[i]);
}else {
res.append("null");
}
if(i != tree.length -1){
res.append(',');
}
}
res.append(']');
return res.toString();
}
}
Trie
对于Trie来说,经常用来处理字符串
package 树;
import java.util.TreeMap;
public class Trie {
private class Node{
boolean isWord;
TreeMap<Character, Node> next;
public Node(boolean isWord){
this.isWord = isWord;
next = new TreeMap<>();
}
public Node(){
this(false);
}
}
private Node root;
private int size;
public Trie(){
root = new Node();
size = 0;
}
public int getSize(){
return size;
}
public void add(String word){
Node cur = root;
for(int i =0;i<word.length();i++){
char c = word.charAt(i);
if(cur.next.get(c) == null){
cur.next.put(c , new Node());
}
cur = cur.next.get(c);
}
if(!cur.isWord){
cur.isWord = true;
size++;
}
}
public boolean contains(String word){
Node cur = root;
for(int i = 0; i<word.length();i++){
char c = word.charAt(i);
if(cur.next.get(c) == null){
return false;
}
cur = cur.next.get(c);
}
return cur.isWord;
}
/**
* 查询是否有单词以prefix为前缀
* */
public boolean isPrefix(String prefix){
Node cur = root;
for(int i = 0;i<prefix.length();i++){
char c = prefix.charAt(i);
if(cur.next.get(c) == null){
return false;
}
cur = cur.next.get(c);
}
return true;
}
public boolean search(String word){
return match(root , word , 0);
}
private boolean match(Node node , String word , int index){
if(index == word.length()){
return node.isWord;
}
char c = word.charAt(index);
if(c !='.'){
if(node.next.get(c) == null){
return false;
}
return match(node.next.get(c) , word , index +1);
}else {
for(char nextChar:node.next.keySet()){
if(match(node.next.get(nextChar) , word , index+1)){
return true;
}
}
return false;
}
}
}
并查集
由孩子指向父亲
package UF;
import java.util.Collections;
public class UnionFind5 implements UF{
private int[] parent;
private int[] rank;
public UnionFind5(int size){
parent = new int[size];
rank = new int[size];
for(int i = 0;i<size;i++){
parent[i] = i;
rank[i] = 1;
}
}
@Override
public int getSize(){
return parent.length;
}
private int find(int p){
if(p < 0 || p >= parent.length){
throw new IllegalArgumentException("p is out of bound");
}
while(p != parent[p]){
parent[p] = parent[parent[p]];
p = parent[p];
}
return p;
}
@Override
public boolean isConnected(int p , int q){
return find(p) == find(q);
}
@Override
public void unionElements(int p , int q){
int pRoot = find(p);
int qRoot = find(q);
if(pRoot == qRoot){
return;
}
//根据两个元素所在树的元素个数不同判断合并方向
//将元素个数少的集合合并到元素个数多的集合上
if(rank[pRoot] < rank[qRoot]){
parent[pRoot] = qRoot;
}else if(rank[qRoot] < rank[pRoot]){
parent[qRoot] = pRoot;
}else{
parent[qRoot] = pRoot;
rank[pRoot] += 1;
}
}
}
AVL
平衡二叉树:对于任意一个节点,左子树和右子树的高度差不能超过1
平衡二叉树的高度和节点数量之间的关系也是O(logn)的
package 树;
import java.util.ArrayList;
public class AVLTree<K extends Comparable<K>,V>{
private class Node{
public K key;
public V value;
public Node left , right;
public int height;
public Node(K key , V value){
this.key = key;
this.value = value;
left = null;
right = null;
height = 1;
}
}
private Node root;
private int size;
public AVLTree(){
root = null;
size = 0;
}
//获得node节点的高度
private int getHeight(Node node){
if(node == null){
return 0;
}
return node.height;
}
//获取平衡因子
public int getBalanceFactor(Node node){
if(node == null){
return 0;
}
return getHeight(node.left) - getHeight(node.right);
}
public int getSize(){
return size;
}
public boolean isEmpty(){
return size == 0;
}
// 判断该二叉树是否是一颗二分搜索树
public boolean isBST(){
ArrayList<K> keys = new ArrayList<>();
inOrder(root , keys);
for(int i = 1; i<keys.size();i++){
if(keys.get(i-1).compareTo(keys.get(i))>0){
return false;
}
}
return true;
}
private void inOrder(Node node , ArrayList<K> keys){
if(node == null){
return;
}
inOrder(node.left , keys);
keys.add(node.key);
inOrder(node.right , keys);
}
// 判断该二叉树是不是一颗平衡二叉树
public boolean isBalanced(){
return isBalanced(root);
}
// 判断以Node为根的二叉树是否是一棵平衡二叉树,递归算法
private boolean isBalanced(Node node){
if(node == null){
return true;
}
int balanceFactor = getBalanceFactor(node);
if(Math.abs(balanceFactor) > 1){
return false;
}
return isBalanced(node.left) && isBalanced(node.right);
}
public void add(K key , V value){
root = add(root , key , value);
}
public V remove(K key) {
Node node = getNode(root , key);
if(node != null){
root = remove(root , key);
return node.value;
}
return null;
}
private Node remove(Node node, K key){
if(node == null){
return null;
}
Node retNode;
if(key.compareTo(node.key) < 0){
node.left = remove(node.left , key);
retNode = node;
} else if(key.compareTo(node.key) > 0){
node.right = remove(node.right , key);
retNode = node;
} else{ // e == node.e
//待删除节点左子树为空的情况
if(node.left == null){
Node rightNode = node.right;
node.right = null;
size --;
retNode = rightNode;
}
//待删除节点右子树为空的情况
else if(node.right == null){
Node leftNode = node.left;
node.left = null;
size --;
retNode = leftNode;
}else {
// 待删除节点左右子树军部为空的情况
// 找到比带删除节点大的最小节点,即待删除节点右子树的最小节点
// 用这个节点顶替待删除节点的位置
Node successor = minimum(node.right);
successor.right = remove(node.right , successor.key);
successor.left = node.left;
node.left = node.right = null;
retNode = successor;
}
}
if(retNode == null){
return null;
}
//更新height
retNode.height = 1 + Math.max(getHeight(retNode.left) , getHeight(retNode.right));
//计算平衡因子
int balanceFactor = getBalanceFactor(retNode);
if(Math.abs(balanceFactor)>1){
System.out.println("unbalanced:"+balanceFactor);
}
// 平衡维护
// LL
if(balanceFactor > 1 && getBalanceFactor(retNode.left) >= 0){
return rightRotate(retNode);
}
// RR
if(balanceFactor < -1 && getBalanceFactor(retNode.right) <= 0){
return leftRotate(retNode);
}
//LR
if(balanceFactor > 1 && getBalanceFactor(retNode.left) < 0){
node.left = leftRotate(retNode.left);
return rightRotate(retNode);
}
//RL
if(balanceFactor < -1 && getBalanceFactor(retNode.right) > 0){
node.right = rightRotate(retNode.right);
return rightRotate(retNode);
}
return retNode;
}
private Node minimum(Node node){
if(node.left == null){
return node;
}
return minimum(node.left);
}
public boolean contains(K key) {
return getNode(root , key) != null;
}
public V get(K key, V newValue) {
Node node = getNode(root , key);
return node == null ? null : node.value;
}
public void set(K key, V newValue) {
Node node = getNode(root , key);
if(node == null){
throw new IllegalArgumentException(key + "doesn't exist!");
}
node.value = newValue;
}
private Node add(Node node , K key , V value){
if(node == null){
size++;
return new Node(key ,value);
}
if(key.compareTo(node.key)<0){
node.left = add(node.left , key , value);
}else if(key.compareTo(node.key)>0){
node.right = add(node.right , key , value);
}else {
node.value = value;
}
//更新height
node.height = 1 + Math.max(getHeight(node.left) , getHeight(node.right));
//计算平衡因子
int balanceFactor = getBalanceFactor(node);
if(Math.abs(balanceFactor)>1){
System.out.println("unbalanced:"+balanceFactor);
}
// 平衡维护
// LL
if(balanceFactor > 1 && getBalanceFactor(node.left) >= 0){
return rightRotate(node);
}
// RR
if(balanceFactor < -1 && getBalanceFactor(node.right) <= 0){
return leftRotate(node);
}
//LR
if(balanceFactor > 1 && getBalanceFactor(node.left) < 0){
node.left = leftRotate(node.left);
return rightRotate(node);
}
//RL
if(balanceFactor < -1 && getBalanceFactor(node.right) > 0){
node.right = rightRotate(node.right);
return rightRotate(node);
}
return node;
}
private Node leftRotate(Node y){
Node x = y.right;
Node T2 = x.left;
//向左旋转过程
x.left = y;
y.right = T2;
//更新height
y.height = Math.max(getHeight(y.left) , getHeight(y.right)) + 1;
x.height = Math.max(getHeight(x.left) , getHeight(x.right)) + 1;
return x;
}
private Node rightRotate(Node y){
Node x = y.left;
Node T3 = x.right;
//向右旋转过程
x.right = y;
y.left = T3;
//更新height
y.height = Math.max(getHeight(y.left) , getHeight(y.right)) + 1;
x.height = Math.max(getHeight(x.left) , getHeight(x.right)) + 1;
return x;
}
private Node getNode(Node node , K key){
if(node == null){
return null;
}
if(key.compareTo(node.key) == 0){
return node;
}else if(key.compareTo(node.key) < 0){
return getNode(node.left , key);
}else {
return getNode(node.right , key);
}
}
}
红黑树
每个节点或者是红色的,或者是黑色的
根节点是黑色的
每一个叶子节点(最后的空节点)是黑色的
如果一个节点是红色的,那么它的孩子节点都是黑色的
从任意一个节点到叶子节点,经过的黑色节点是一样的
图
概念:图是由顶点和边组成的数据结构
在有向图中,细分为入度和出度。边可以有权重,代表从源顶点到目标顶点的距离、费用、时间或者其他度量
以上就是近期学习的所有API,红黑树和图没有实现代码是因为这两个实现比较复杂,而且图的应用算法基本上都是困难级别。所以可能会在之后的博客中单开几篇去讲他们。