目录
1.二分查找
public class BinarySearch {
public static int binarySerchBasic(int []a,int target){
int i=0,j=a.length-1;
while (i<=j){
int m=(i+j)/2;
if(target<a[m]){
j=m-1;
} else if (a[m]<target) {
i=m+1;
}else {
return m;
}
}
return -1;
}
}
为什么是i<=j意味着区间内有为比较的元素,而不是i<j?
i==j,意味着i,j他们指向的元素也会参与比较
i<j只意味着m指向的元素参与比较
(i+j)/2有没有问题?
可以把除以2换成>>>1
都写成小于号有啥好处?
public class BinarySearch {
public static int binarySerchBasic(int []a,int target){
int i=0,j=a.length;
while (i<j){
int m=(i+j)>>>1;
if(target<a[m]){
j=m;
} else if (a[m]<target) {
i=m+1;
}else {
return m;
}
}
return -1;
}
}
Leftmost
public static int binarySerchBasic(int []a,int target){
int i=0,j=a.length-1;
int condiate=-1;
while (i<=j){
int m=(i+j)>>>1;
if(target<a[m]){
j=m-1;
} else if (a[m]<target) {
i=m+1;
}else {
condiate=m;
j=m-1;
}
}
return condiate;
}
Rightmost
public static int binarySerchBasic(int []a,int target){
int i=0,j=a.length-1;
int condiate=-1;
while (i<=j){
int m=(i+j)>>>1;
if(target<a[m]){
j=m-1;
} else if (a[m]<target) {
i=m+1;
}else {
condiate=m;
j=m+1;
}
}
return condiate;
}
求前任:leftmost(4)-1
求后任:rightmost(4)+1
2.数组
在计算机科学中,数组是由一组变量组成的数据结构,每个元素有一个索引
因为数组是连续存储的,所以数组中元素的地址,可以通过其索引计算出来
public class DynamicArray {
private int size=0;
private int capacity=8;
private int[]array= {};
public void addLast(int element){
array[size]=element;
size++;
}
public void add(int index,int element){
checkAndGrow();
if(index>=0&&index<size){
System.arraycopy(array,index,array,index+1,size-index);
}
array[index]=element;
size++;
}
private 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;
}
}
public int get(int index){
return array[index];
}
public void forEach(Consumer<Integer>consumer){
for (int i = 0; i < size; i++) {
// System.out.println(array[i]);
consumer.accept(array[i]);
}
}
public int remove(int index){
int removed=array[index];
System.arraycopy(array,index+1,array,index,size-index-1);
size--;
return removed;
}
}
3.链表
在计算机科学中,链表是数据元素的现形记和,其每个元素都指向先一个元素,元素存储上并不连续
public class SingLinkedList {
private Node head=null;
private static class Node{
int vlaue;
Node next;
public Node(int vlaue,Node next){
this.next=next;
this.vlaue=vlaue;
}
}
public void addFirst(int value){
head=new Node(value,head);
}
public void loop1(){
Node p=head;
while (p!=null){
System.out.println(p.vlaue);
p=p.next;
}
}
public void loop2(Consumer<Integer> consumer){
for (Node p=head;p!=null;p=p.next){
consumer.accept(p.vlaue);
}
}
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);
return;
}
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.vlaue;
}
private IllegalArgumentException illegalIndex(int index){
return new IllegalArgumentException(String.format("index[%d] 不合法%n",index));
}
public void insert(int index,int value) throws IllegalArgumentException{
if(index==0){
addFirst(value);
return;
}
Node pre=findNode(index-1);
if(pre==null){
throw illegalIndex(index);
}
pre.next=new Node(value,pre.next);
}
public void removeFirst(){
if(head==null){
throw illegalIndex(0);
}
head=head.next;
}
public void remove(int index){
if(index==0){
removeFirst();
return;
}
Node prev=findNode(index-1);
if(prev==null){
throw illegalIndex(index);
}
Node removed=prev.next;
if(removed==null){
throw illegalIndex(index);
}
prev.next=removed.next;
}
}
双向链表带哨兵
public class DoublyLinkedListSentinel implements Iterator<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 illegalIndex(index);
}
Node next=prev.next;
Node inserted=new Node(prev,value, next);
prev.next=inserted;
next.prev=inserted;
}
public void remove(int index){
Node prev=findNode(index-1);
if(prev==null){
throw illegalIndex(index);
}
Node removed=prev.next;
if(removed==tail){
throw illegalIndex(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;
if(removed==head){
throw illegalIndex(0);
}
Node prev=removed.prev;
prev.next=tail;
tail.prev=prev;
}
@Override
public boolean hasNext() {
return false;
}
@Override
public Integer next() {
return null;
}
public Iterator<Integer>iterator(){
return new Iterator<Integer>() {
Node p=head.next;
@Override
public boolean hasNext() {
return p!=tail;
}
@Override
public Integer next() {
int value=p.value;
p=p.next;
return value;
}
};
}
private IllegalArgumentException illegalIndex(int index){
return new IllegalArgumentException(String.format("index[%d] 不合法%n",index));
}
}
双向环形链表
public class DoublyLinkedListSentinel1 {
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 DoublyLinkedListSentinel1(){
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 a=sentinel.prev;
Node b=sentinel;
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;
Node a=removed.prev;
Node b=sentinel;
a.next=b;
b.prev=a;
}
}
4.递归
定义:计算机科学中,递归是一种解决计算问题得方法,其中解决方案取决于同一类问题的更小子集
void f(Node node){
if(node==null){
return;
}
f(node.next);
}
自己调用自己,如果说每个函数对应着一种解决方案,自己调用自己意味着解决方案是一样的(有规律的)
每次调用,函数处理的数据会较上次缩减,而且最后会缩减至无需继续递归
内层函数调用完成,外层函数才能算调用完成
1.确定能否使用递归求解
2.深入到最里层叫做递
从最里层出来叫做归
在递的过程中,外层函数内的局部变量(以及方法参数)并未消失,归的时候还可以用到
public class ReversePrintString {
public static void f(int n,String str){
if (n==str.length()){
return;
}
f(n+1,str);
System.out.println(str.charAt(n));
}
public static void main(String[] args) {
f(0,"abcde");
}
}
递归二分查找算法
public class E03BinarySearch {
public static int search(int []a,int target){
return -1;
}
public static int f(int[]a,int target,int i,int j){
if(i>j){
return -1;
}
int m=(i+j)>>>1;
if(target<a[m]){
return f(a,target,i,m-1);
} else if (a[m]<target) {
return f(a,target,m+1,j);
}else{
return m;
}
}
}
递归冒泡排序算法
public class E04BuddleSort {
private static void buddle(int[]a){
for (int i=0;i<a.length-1;i++){
for(int j=i+1;j<a.length;j++){
if(a[i]>a[j]){
int target=a[i];
a[i]=a[j];
a[j]=target;
}
}
}
}
private static void buddle1(int []a,int j){
if(j==0){
return;
}
for(int i=0;i<j;i++){
if(a[i]>a[i+1]){
int t=a[i];
a[i]=a[i+1];
a[i+1]=t;
}
}
buddle1(a,j-1);
}
public static void sort(int []a){
buddle1(a,a.length-1);
}
private static void buddle2(int []a,int j){
if(j==0){
return;
}
int x=0;
for(int i=0;i<j;i++){
if(a[i]>a[i+1]){
int t=a[i];
a[i]=a[i+1];
a[i+1]=t;
x=i;
}
}
buddle1(a,x);
}
public static void main(String[] args) {
int[]a={2,1,8,5,3,4};
sort(a);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]);
}
}
}
插入排序递归算法
public class E05InsertionSort {
public static void sort(int[]a){
insertion2(a,1);
}
public static void insertion(int[]a,int low){
if(low==a.length){
return ;
}
int t=a[low];
int i=low-1;
while (i>=0&&a[i]>t){
a[i+1]=a[i];
i--;
}
if(i+1!=low){
a[i+1]=t;
}
insertion(a,low+1);
}
public static void insertion2(int[]a,int low){
if(low==a.length){
return ;
}
int i=low-1;
while (i>=0&&a[i]>a[i+1]){
int t=a[i];
a[i]=a[i+1];
a[i+1]=t;
i--;
}
insertion2(a,low+1);
}
public static void main(String[] args) {
int[]a={2,1,8,5,3,4};
sort(a);
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]);
}
}
}
斐波那契数列
记忆法求斐波那契数列
public static int fibonacci(int n){
int[]cache=new int[n+1];
Arrays.fill(cache,-1);
cache[0]=0;
cache[1]=1;
return f1(n,cache);
}
public static int f1(int n,int[]cache){
if (cache[n]!=-1){
return cache[n];
}
int x=f1(n-1,cache);
int y=f1(n-2,cache);
cache[n]=x+y;
return cache[n];
}
爆栈问题
当递归调用次数太多,没到最深的那一次后都不能释放函数,而外层函数都在占用内存导致爆栈
尾调用
如果函数的最后一步是调用一个函数,那么称为尾调用
避免爆栈问题就将递归改成循环
public class HanoiTower {
static LinkedList<Integer> a=new LinkedList<>();
static LinkedList<Integer> b=new LinkedList<>();
static LinkedList<Integer> c=new LinkedList<>();
static void init(int n){
for (int i = n; i >=1 ; i--) {
a.addLast(i);
}
}
static void move(int n,LinkedList<Integer>a,
LinkedList<Integer>b,
LinkedList<Integer>c){
if(n==0){
return ;
}
move(n-1,a,c,b);
c.addLast(a.removeLast());
print();
move(n-1,b,a,c);
}
public static void main(String[] args) {
init(3);
print();
move(3,a,b,c);
}
private static void print() {
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println("---------------");
}
}
时间复杂度
杨辉三角
public class PascalTriangle {
private static int element1(int i,int j){
if(j==0||i==j){
return 1;
}
return element1(i-1,j-1)+element1(i-1,j);
}
public static void print1(int n){
for (int i = 0; i < n; i++) {
printSpace1(n,i);
for (int j=0;j<=i;j++){
System.out.printf("%-4d",element1(i,j));
}
System.out.println();
}
}
private static void printSpace1(int n,int i){
int num=(n-1-i)*2;
for(int j=0;j<num;j++){
System.out.print(" ");
}
}
public static void main(String[] args) {
print2(5);
}
private static int element(int [][]triangle,int i,int j){
if(triangle[i][j]>0){
return triangle[i][j];
}
if(j==0||i==j){
triangle[i][j]=1;
return 1;
}
triangle[i][j]= element(triangle,i-1,j-1)+element(triangle,i-1,j);
return triangle[i][j];
}
public static void print(int n){
int[][]triangle=new int[n][];
for (int i = 0; i < n; i++) {
triangle[i]=new int[i+1];
//printSpace1(n,i);
for (int j=0;j<=i;j++){
System.out.printf("%-4d",element1(i,j));
}
System.out.println();
}
}
private static void printSpace(int n,int i){
int num=(n-1-i)*2;
for(int j=0;j<num;j++){
System.out.print(" ");
}
}
private static void createRow(int []row,int i){
if(i==0){
row[0]=1;
return ;
}
for(int j=i;j>0;j--){
row[j]=row[j]+row[j-1];
}
}
public static void print2(int n){
int []row=new int[n];
for (int i = 0; i < n; i++) {
createRow(row,i);
//printSpace1(n,i);
for (int j=0;j<=i;j++){
System.out.printf("%-4d",row[j]);
}
System.out.println();
}
}
}
反转链表
public class Leetcode206 {
public LinkNode reverseList4(LinkNode o1){
if(o1==null||o1.next==null){
return o1;
}
LinkNode n1=null;
while (o1!=null){
LinkNode o2=o1.next;
o1.next=n1;
n1=o1;
o1=o2;
}
return n1;
}
public LinkNode reverseList3(LinkNode o1){
LinkNode o2=o1.next;
LinkNode n1=o1;
while (o2!=null){
o1.next=o2.next;
o2.next=n1;
n1=o2;
o2=o1.next;
}
return n1;
}
public LinkNode reverseList2(LinkNode p){
if(p==null||p.next==null){
return p;
}
LinkNode last=reverseList2(p.next);
p.next.next=p;
p.next=null;
return last;
}
public LinkNode reverserList1(LinkNode o1){
List list1=new List(o1);
List list2=new List(null);
while (true){
LinkNode first=list1.removeFirst();
if(first==null){
break;
}
list2.addFirst(first);
}
return list2.head;
}
public LinkNode reverserList(LinkNode o1){
LinkNode n1=null;
LinkNode p=o1;
while (p!=null){
n1=new LinkNode(p.value,n1);
p=p.next;
}
return n1;
}
static class List{
LinkNode head;
public List(LinkNode head) {
this.head = head;
}
public void addFirst(LinkNode first){
first.next=head;
head=first;
}
public LinkNode removeFirst(){
LinkNode first =head;
if(first!=null){
head=first.next;
}
return first;
}
}
public static void main(String[] args) {
LinkNode o5=new LinkNode(5,null);
LinkNode o4=new LinkNode(4,o5);
LinkNode o3=new LinkNode(3,o4);
LinkNode o2=new LinkNode(2,o3);
LinkNode o1=new LinkNode(1,o2);
System.out.println(o1);
LinkNode n1=new Leetcode206().reverseList4(o1);
System.out.println(n1);
}
}
根据值删除节点
public class LeetCode203 {
public LinkNode removeElement(LinkNode head,int val){
LinkNode s=new LinkNode(-1,head);
LinkNode p1=s;
LinkNode p2=s.next;
while (p2!=null){
if(p2.value==val){
p1.next=p2.next;
p2=p2.next;
}
else{
p1=p1.next;
p2=p2.next;
}
}
return s.next;
}
public LinkNode removeElements(LinkNode p,int val){
if(p==null){
return null;
}
if(p.value==val){
return removeElement(p.next,val);
}
else{
p.next=removeElement(p.next,val);
return p;
}
}
}
删除倒数节点
public class LeetCode19 {
public LinkNode removeNthFromEnd(LinkNode head,int n){
LinkNode s=new LinkNode(-1,head);
recursion(head,n);
return head;
}
public LinkNode removeNthFromEnd1(LinkNode head,int n){
LinkNode s=new LinkNode(-1,head);
LinkNode p1=s;
LinkNode p2=s;
for (int i = 0; i < n+1; i++) {
p2=p2.next;
}
while (p2!=null){
p1=p1.next;
p2=p2.next;
}
p1.next=p1.next.next;
return s.next;
}
private int recursion(LinkNode p,int n){
if(p==null){
return 0;
}
int nth=recursion(p.next,n);
System.out.println(p.value+" "+nth);
if(nth==n){
p.next=p.next.next;
}
return nth+1;
}
public static void main(String[] args) {
}
}
删除有序链表重复节点
public class LeetCode83 {
public LinkNode deleteDuplicate(LinkNode head){
if(head==null||head.next==null){
return head;
}
LinkNode p1=head;
LinkNode p2;
while ((p2=p1.next)!=null){
if(p1.value==p2.value){
p1.next=p2.next;
}else{
p1=p1.next;
}
}
return head;
}
public LinkNode deleteDuplicate1(LinkNode p){
if(p==null||p.next==null){
return p;
}
if(p.value==p.next.value){
return deleteDuplicate1(p.next);
}
else {
p.next=deleteDuplicate1(p.next);
return p;
}
}
}
有序链表去重
public class LeetCode82 {
public LinkNode deleteDuplicates(LinkNode p){
if(p==null||p.next==null){
return p;
}
if(p.value==p.next.value){
LinkNode x=p.next.next;
while (x!=null&&x.value==p.value){
x=x.next;
}
return deleteDuplicates(x);
}
else{
p.next=deleteDuplicates(p.next);
return p;
}
}
public LinkNode deleteDuplicates1(LinkNode head){
if(head==null||head.next==null){
return head;
}
LinkNode s=new LinkNode(-1,head);
LinkNode p1=s;
LinkNode p2,p3;
while ((p2 = p1.next) != null && (p3 = p2.next) != null) {
if(p2.value==p3.value){
while ((p3=p3.next)!=null&&p3.value==p2.value){
}
p1.next=p3;
}else{
p1=p1.next;
}
}
return s.next;
}
}
合并有序链表
public class LeetCode21 {
public LinkNode mergeTwoLists(LinkNode p1,LinkNode p2){
LinkNode s=new LinkNode(-1,null);
LinkNode p=s;
while (p1!=null&&p2!=null){
if(p1.value<p2.value){
p.next=p1;
p1=p1.next;
}else{
p.next=p2;
p2=p2.next;
}
p=p.next;
}
if(p1!=null){
p.next=p1;
}
if(p2!=null){
p.next=p2;
}
return s.next;
}
public LinkNode mergeTwoLists1(LinkNode p1,LinkNode p2){
if(p2==null){
return p1;
}
if(p1==null){
return p2;
}
if(p1.value<p2.value){
p1.next=mergeTwoLists1(p1.next,p2);
return p1;
}
else{
p2.next=mergeTwoLists1(p1,p2.next);
return p2;
}
}
}
合并K个升序链表
public LinkNode mergeKLists(LinkNode[] lists){
if(lists.length==0){
return null;
}
return split(lists,0,lists.length-1);
}
private LinkNode split(LinkNode[]lists,int i,int j){
int m=(i+j)>>>1;
LinkNode left=split(lists,i,m);
LinkNode right=split(lists,m+1,j);
return mergeTwoLists(left,right);
}
查找链表的中间节点和回文链表
public class LeetCode876 {
public LinkNode middleNode(LinkNode head){
LinkNode p1=head;
LinkNode p2=head;
while (p2!=null&&p2.next!=null){
p1=p1.next;
p2=p2.next;
p2=p2.next;
}
return p1;
}
private LinkNode reverse(LinkNode o1){
LinkNode n1=null;
while (o1!=null){
LinkNode o2=o1.next;
o1.next=n1;
n1=o1;
o1=o2;
}
return n1;
}
}
环形算法
public class LeetCode142 {
public LinkNode detectCycle(LinkNode head){
LinkNode h=head;
LinkNode t=head;
while (h!=null&&h.next!=null){
t=t.next;
h=h.next.next;
if(h==t){
t=head;
while (true){
if(t==h){
return t;
}
t=t.next;
h=h.next;
}
}
}
return null;
}
}
合并有序数组
public class SortedArray {
public static void main(String[] args) {
int []a1={1,5,6,2,4,10,11};
int []a2=new int[a1.length];
merge(a1,0,2,3,6,a2,0);
System.out.println(Arrays.toString(a2));
}
public static void merge(int []a1,int i,int iEnd,int j,int jEnd,int[]a2,int k){
if(i>iEnd){
System.arraycopy(a1,j,a2,k,jEnd-j+1);
return;
}
if(j>jEnd){
System.arraycopy(a1,i,a2,k,iEnd-i+1);
return;
}
if(a1[i]<a1[j]){
a2[k]=a1[i];
merge(a1,i+1,iEnd,j,jEnd,a2,k+1);
}else{
a2[k]=a1[j];
merge(a1,i,iEnd,j+1,jEnd,a2,k+1);
}
}
public static void merge1(int []a1,int i,int iEnd,int j,int jEnd,int[]a2){
int k=0;
while (i<=iEnd&&j<=jEnd){
if(a1[i]<a1[j]){
a2[k]=a1[i];
i++;
}else{
a2[k]=a1[k];
j++;
}
k++;
}
if(i>iEnd){
System.arraycopy(a1,j,a2,k,jEnd-j+1);
}
if(j>jEnd){
System.arraycopy(a1,i,a2,k,iEnd-i+1);
}
}
}
5.队列
计算机科学中,queue是以顺序的方式维护的一组数据集合,在一端添加数据,从另一端移除数据,习惯来说,添加的一端称为尾,移除的一端称为头,就如同生活中的排队买东西。
public class LinkedListQueue<E> implements Queue<E>, Iterator<E> {
@Override
public boolean hasNext() {
return false;
}
@Override
public E next() {
return null;
}
private static class Node<E>{
E value;
Node<E>next;
public Node(E value,Node<E>next){
this.value=value;
this.next=next;
}
}
Node<E> head=new Node<>(null,null);
Node<E> tail=head;
private int size;
private int capacity=Integer.MAX_VALUE;
public LinkedListQueue(int capacity){
this.capacity=capacity;
}
public LinkedListQueue() {
tail.next=head;
}
@Override
public boolean isEmpty() {
return tail==head;
}
@Override
public boolean isFull() {
return size==capacity;
}
@Override
public boolean offer(E value) {
if(isFull()){
return false;
}
Node<E> added=new Node<>(value,head);
tail.next=added;
tail=added;
return true;
}
@Override
public E poll() {
if(isEmpty()){
return null;
}
Node<E>first=head.next;
head.next=first.next;
if(first==tail){
tail=head;
}
return first.value;
}
@Override
public E peek() {
if(isEmpty()){
return null;
}
return head.next.value;
}
}
public class ArrayQueue1<E> implements Queue<E> {
private E[]array;
private int head=0;
private int tail=0;
public ArrayQueue1(int capacity) {
array=(E[])new Object[capacity+1];
}
@Override
public boolean offer(E value) {
if(isFull()){
return false;
}
array[tail]=value;
tail=(tail+1)%array.length;
return true;
}
@Override
public E poll() {
if(isEmpty()){
return null;
}
E value=array[head];
head=(head+1)%array.length;
return value;
}
@Override
public E peek() {
if(isEmpty()){
return null;
}
return array[head];
}
@Override
public boolean isEmpty() {
return head==tail;
}
@Override
public boolean isFull() {
return (tail+1)%array.length==head;
}
}
public class ArrayQueie2<E> implements Queue<E>{
private final E[]array;
private int head=0;
private int tail=0;
public ArrayQueie2(int capacity) {
array=(E[])new Object[capacity];
}
@Override
public boolean offer(E value) {
if (isFull()){
return false;
}
array[tail% array.length]=value;
tail++;
return true;
}
@Override
public E poll() {
if(isEmpty()){
return null;
}
E value=array[head% array.length];
head++;
return value;
}
@Override
public E peek() {
if(isEmpty()){
return null;
}
E value=array[head% array.length];
return value;
}
@Override
public boolean isEmpty() {
return head==tail;
}
@Override
public boolean isFull() {
return tail-head==array.length;
}
}
求模运算
如果除数是2的n次方
那么被除数的后n位即为余数
求被除数的后n位方法,与2^n-1按位与
6.栈
在计算机科学中,stack是一种线性的数据结构,只能在其一端添加数据和移除数据。习惯来说,这一端称之为栈顶,另一端不能操作数据的称之为栈底,就如同生活中的一摞书。
基于链表的实现
public class LinkedListStack<E> implements Stack<E>{
private int capacity;
private int size;
private Node<E>head=new Node<>(null,null);
public LinkedListStack(int capacity) {
this.capacity = capacity;
}
static class Node<E>{
E value;
Node<E>next;
public Node(E value, Node<E> next) {
this.value = value;
this.next = next;
}
}
@Override
public boolean push(E value) {
if(isFull()){
return false;
}
head.next=new Node<>(value,head.next);
size++;
return true;
}
@Override
public E pop() {
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.next==null;
}
@Override
public boolean isFull() {
return size==capacity;
}
}
基于数组的实现
package com.datastructure;
public class ArrayStack<E> implements Stack<E> {
private E[] array;
private int top;
public ArrayStack(int capacity){
this.array=(E[]) new Object[capacity];
}
@Override
public boolean push(E value) {
if(isFull()){
return false;
}
array[top]=value;
top++;
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;
}
}
public class LeetCode20 {
public boolean isValid(String s){
ArrayStack<Character> stack=new ArrayStack<>(s.length());
for (int i = 0; i < s.length(); i++) {
char c=s.charAt(i);
if(c=='('){
stack.push(')');
} else if (c=='[') {
stack.push(']');
} else if (c=='{') {
stack.push('}');
}else{
if(!stack.isEmpty()&&c==stack.peek()){
stack.pop();
}else{
return false;
}
}
}
return stack.isEmpty();
}
}
public class Leetcode150 {
public int evalPRN(String []tokens){
LinkedList<Integer> stack =new LinkedList<>();
for (String t : tokens) {
switch (t){
case "+"->{
Integer b=stack.pop();
Integer a=stack.pop();
stack.push(a+b);
}
case "-"->{
Integer b=stack.pop();
Integer a=stack.pop();
stack.push(a-b);
}
case "*"->{
Integer b=stack.pop();
Integer a=stack.pop();
stack.push(a*b);
}
case "/"->{
Integer b=stack.pop();
Integer a=stack.pop();
stack.push(a/b);
}
default -> {
stack.push(Integer.parseInt(t));
}
}
}
return stack.pop();
}
}
public class InfixToSuffix {
//1.遇到非运算符直接拼串
//2.遇到+-*/
//它的优先级比栈顶运算符搞,入栈
//否则把栈里优先级>=它的都出战,它再入栈
//遍历完成,栈里剩余运算符依次出栈
//左括号直接入栈,左括号优先设置0
static int priority(char c){
return switch (c){
case '*','/'->2;
case '+','-'->1;
case '(',')'->0;
default -> throw new IllegalArgumentException("不合法的运算符:"+c);
};
}
static String infixToSuffix(String exp){
LinkedList<Character> stack=new LinkedList<>();
StringBuilder sb=new StringBuilder(exp.length());
for (int i = 0; i < exp.length(); i++) {
char c=exp.charAt(i);
switch (c){
case '*','/','+','-'->{
if(stack.isEmpty()){
stack.push(c);
}else {
if (priority(c)>priority(stack.peek())) {
stack.push(c);
}else{
while (!stack.isEmpty()&&priority(stack.peek())>=priority(c)){
sb.append(stack.pop());
}
stack.push(c);
}
}
}
case '(' ->{
stack.push(c);
}
case ')' ->{
while (!stack.isEmpty()&&stack.peek()!='('){
sb.append(stack.pop());
}
stack.pop();
}
default -> {
sb.append(c);
}
}
}
while (!stack.isEmpty()){
sb.append(stack.pop());
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(infixToSuffix("a+b"));
System.out.println(infixToSuffix("a+b-c"));
System.out.println(infixToSuffix("a*b+c"));
System.out.println(infixToSuffix("(a+b)*c"));
}
}
public class LeetCode232 {
ArrayStack<Integer>s1=new ArrayStack<>(100);
ArrayStack<Integer>s2=new ArrayStack<>(100);
public void push(int x){
s2.push(x);
}
public int pop(){
if(s1.isEmpty()){
while (!s2.isEmpty()){
s1.push(s2.pop());
}
}
return s1.pop();
}
public int peek(){
if(s1.isEmpty()){
while (!s2.isEmpty()){
s1.push(s2.pop());
}
}
return s1.peek();
}
public boolean empty(){
return s1.isEmpty()&&s2.isEmpty();
}
}
一个队列实现栈
public class LeetCode225 {
private int size;
ArrayQueie2<Integer>queue=new ArrayQueie2<>(100);
public void push(int x){
queue.offer(x);
for (int i = 0; i < size; i++) {
queue.offer(queue.poll());
}
size++;
};
public int pop(){
size--;
return queue.poll();
}
public int top(){
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}
双端队列
基于链表实现
public class LinkedListDeque <E> implements Deque<E>{
static class Node<E>{
Node<E> prev;
private 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;
}
@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 true;
}
@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;
}
}
基于数组实现
public class ArrayDeque1<E> implements Deque<E>{
static int inc(int i,int length){
if(i+1>=length){
return 0;
}
return i+1;
}
static int dec(int i,int length){
if(i-1<0){
return length-1;
}
return i-1;
}
E[]array;
int head;
int tail;
public ArrayDeque1(int capacity){
array = (E[]) new Object[capacity + 1];
}
@Override
public boolean offerFirst(E e) {
if(isFull()){
return false;
}
head=dec(head,array.length);
array[head]=e;
return true;
}
@Override
public boolean offerLast(E e) {
if(isFull()){
return false;
}
array[tail]=e;
tail=inc(tail,array.length);
return true;
}
@Override
public E pollFirst() {
if(isEmpty()){
return null;
}
E e=array[head];
head=inc(head, array.length);
return e;
}
@Override
public E pollLast() {
if(isEmpty()){
return null;
}
tail=dec(tail,array.length);
return array[tail];
}
@Override
public E peekFirst() {
if(isEmpty()){
return null;
}
return array[head];
}
@Override
public E peekLast() {
if(isEmpty()){
return null;
}
return array[dec(tail,array.length)];
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean isFull() {
if(tail>head){
return tail-head==array.length-1;
} else if (tail<head) {
return head-tail==1;
}else{
return false;
}
}
}
无序数组实现优先级队列
public class PriorityQueue1 <E extends Priority> implements Queue<E>{
Priority[]array;
int size;
public PriorityQueue1(int capacity) {
array=new Priority[capacity];
}
@Override
public boolean offer(E value) {
if(isFull()){
return false;
}
array[size++]=value;
return true;
}
private int selectMax(){
int max=0;
for (int i = 0; i < size; i++) {
if(array[i].priority()>array[max].priority()){
max=i;
}
}
return max;
}
@Override
public E poll() {
if(isEmpty()){
return null;
}
int max=selectMax();
E e= (E) array[max];
remove(max);
return e;
}
private void remove(int index){
if(index<size-1){
System.arraycopy(array,index+1,array,index,size-1-index);
}
size--;
}
@Override
public E peek() {
if(isEmpty()){
return null;
}
int max=selectMax();
return (E) array[max];
}
@Override
public boolean isEmpty() {
return size==0;
}
@Override
public boolean isFull() {
return size==array.length;
}
}
有序数组实现
public class PriorityQueue2 <E extends Priority> implements Queue<E>{
@Override
public boolean offer(E value) {
if(isFull()){
return false;
}
insert(value);
size++;
return true;
}
private void insert(E e){
int i=size-1;
while (i>=0&&array[i].priority()>e.priority()){
array[i+1]=array[i];
i--;
}
array[i+1]=e;
}
Priority[]array;
int size;
public PriorityQueue2(int capacity) {
array=new Priority[capacity];
}
@Override
public E poll() {
if(isEmpty()){
return null;
}
E e=(E)array[size-1];
size--;
array[size]=null;
return e;
}
@Override
public E peek() {
if (isEmpty()){
return null;
}
return (E)array[size-1];
}
@Override
public boolean isEmpty() {
return size==0;
}
@Override
public boolean isFull() {
return size==array.length;
}
}
堆实现
在计算机科学中,堆是一种基于数的数据结构,通常用完全二叉树实现。
大顶堆:任意父节点都比他的两个孩子都大
小顶堆:任意父节点都比他的两个孩子都小
public class PriorityQueue4 <E extends Priority> implements Queue<E>{
Priority[]array;
int size;
public PriorityQueue4(int capacity) {
array=new Priority[capacity];
}
@Override
public boolean offer(E value) {
if(isFull()){
return false;
}
int child=size++;
int parent=(child-1)/2;
while (child>0&&value.priority()>array[parent].priority()){
array[child]=array[parent];
child=parent;
parent=(child-1)/2;
}
array[child]=value;
return true;
}
private void swap(int i,int j){
Priority t=array[i];
array[i]=array[j];
array[j]=t;
}
@Override
public E poll() {
if(isEmpty()){
return null;
}
swap(0,size-1);
size--;
Priority e=array[size];
array[size]=null;
down(0);
return (E) e;
}
private void down(int parent){
int left=2*parent+1;
int right=left+1;
int max=parent;
if(left<size&&array[left].priority()>array[max].priority()){
left=max;
}
if(right<size&&array[right].priority()>array[max].priority()){
right=max;
}
if(max!=parent){
swap(max,parent);
down(max);
}
}
@Override
public E peek() {
if(isEmpty()){
return null;
}
return (E)array[0];
}
@Override
public boolean isEmpty() {
return size==0;
}
@Override
public boolean isFull() {
return size==array.length;
}
}
阻塞队列
public class BlockingQueue1 <E> implements BlockingQueue<E>{
private final E[] array;
private int head;
private int tail;
private int size;
public BlockingQueue1(int capacity) {
array= (E[]) new Object[capacity];
}
private ReentrantLock lock=new ReentrantLock();
private Condition headWaits=lock.newCondition();
private Condition tailWaits=lock.newCondition();
public boolean isEmpty(){
return size==0;
}
public boolean isFull(){
return size==array.length;
}
@Override
public void offer(E e) throws InterruptedException {
lock.lockInterruptibly();
try {
while (isFull()){
tailWaits.await();
}
array[tail]=e;
if(++tail==array.length){
tail=0;
}
size++;
headWaits.signal();
}finally {
lock.unlock();
}
}
@Override
public boolean offer(E e, long timeout) throws InterruptedException {
lock.lockInterruptibly();
try {
long t= TimeUnit.MILLISECONDS.toNanos(timeout);
while (isFull()){
if(t<=0){
return false;
}
tailWaits.awaitNanos(t);//最多等待多少纳秒
}
array[tail]=e;
if(++tail==array.length){
tail=0;
}
size++;
headWaits.signal();
return true;
}finally {
lock.unlock();
}
}
@Override
public E poll() throws InterruptedException {
lock.lockInterruptibly();
try {
while (isEmpty()){
headWaits.await();
}
E e=array[head];
array[head]=null;
if(++head==array.length){
head=0;
}
size--;
tailWaits.signal();
return e;
}finally {
lock.unlock();
}
}
}
public interface BlockingQueue <E>{
void offer(E e) throws InterruptedException;
boolean offer(E e,long timeout) throws InterruptedException;
E poll() throws InterruptedException;
}
7.堆
public class MaxHeap {
int []array;
int size;
public MaxHeap(int capacity) {
this.array=new int[capacity];
}
public MaxHeap(int []array){
this.array=array;
this.size=array.length;
heapify();
}
private void heapify(){
for (int i = size/2-1; i >=0 ; i--) {
down(i);
}
}
private void down(int parent) {
int left=parent*2+1;
int right=left+1;
int max=parent;
if(left<size&&array[left]>array[max]){
max=left;
}
if(right<size&&array[right]>array[max]){
max=right;
}
if(max!=parent){
swap(max,parent);
down(max);
}
}
private void swap(int max, int parent) {
int t=array[max];
array[max]=array[parent];
array[parent]=t;
}
public void replace(int replaced){
array[0]=replaced;
down(0);
}
public boolean offer(int offered){
if(size==array.length){
return false;
}
up(offered);
size++;
return true;
}
private void up(int offered) {
int child=size;
while(child>0){
int parent=(child-1)/2;
if(offered>array[parent]){
array[child]=array[parent];
}else{
break;
}
child=parent;
}
array[child]=offered;
}
public static void main(String[] args) {
int []array={1,2,3,4,5,6,7};
MaxHeap maxHeap = new MaxHeap(array);
System.out.println(Arrays.toString(maxHeap.array));
int[]array1={2,3,1,7,6,4,5};
MaxHeap maxHeap1 = new MaxHeap(array1);
while (maxHeap1.size>1){
maxHeap1.swap(0, maxHeap1.size-1);
maxHeap1.size--;
maxHeap1.down(0);
}
System.out.println(Arrays.toString(maxHeap1.array));
}
public int peek(){
return array[0];
}
public int poll(){
int top=array[0];
swap(0,size-1);
size--;
down(0);
return top;
}
public int poll(int index){
int delete=array[index];
swap(index,size-1);
size--;
down(index);
return delete;
}
}
public class MinHeap {
int []array;
int size;
public MinHeap(int capacity) {
this.array=new int[capacity];
}
public MinHeap(int []array){
this.array=array;
this.size=array.length;
heapify();
}
private void heapify(){
for (int i = size/2-1; i >=0 ; i--) {
down(i);
}
}
private void down(int parent) {
int left=parent*2+1;
int right=left+1;
int max=parent;
if(left<size&&array[left]<array[max]){
max=left;
}
if(right<size&&array[right]<array[max]){
max=right;
}
if(max!=parent){
swap(max,parent);
down(max);
}
}
private void swap(int max, int parent) {
int t=array[max];
array[max]=array[parent];
array[parent]=t;
}
public void replace(int replaced){
array[0]=replaced;
down(0);
}
public boolean offer(int offered){
if(size==array.length){
return false;
}
up(offered);
size++;
return true;
}
private void up(int offered) {
int child=size;
while(child>0){
int parent=(child-1)/2;
if(offered<array[parent]){
array[child]=array[parent];
}else{
break;
}
child=parent;
}
array[child]=offered;
}
public static void main(String[] args) {
System.out.println(findKthLargest(new int[]{3,2,1,5,6,4},2));
}
public int peek(){
return array[0];
}
public int poll(){
int top=array[0];
swap(0,size-1);
size--;
down(0);
return top;
}
public int poll(int index){
int delete=array[index];
swap(index,size-1);
size--;
down(index);
return delete;
}
public static int findKthLargest(int[] numbers, int k){
MinHeap heap=new MinHeap(k);
for (int i = 0; i < k; i++) {
heap.offer(numbers[i]);
}
for (int i = k; i < numbers.length; i++) {
if(numbers[i]>heap.peek()){
heap.replace(numbers[i]);
}
}
return heap.peek();
}
}
package com.datastructure;
import java.util.Arrays;
/**
* 可以扩容的 heap, max 用于指定是大顶堆还是小顶堆
*/
public class Heap {
int[] array;
int size;
boolean max;
public int size() {
return size;
}
public Heap(int capacity, boolean max) {
this.array = new int[capacity];
this.max = max;
}
/**
* 获取堆顶元素
*
* @return 堆顶元素
*/
public int peek() {
return array[0];
}
/**
* 删除堆顶元素
*
* @return 堆顶元素
*/
public int poll() {
int top = array[0];
swap(0, size - 1);
size--;
down(0);
return top;
}
/**
* 删除指定索引处元素
*
* @param index 索引
* @return 被删除元素
*/
public int poll(int index) {
int deleted = array[index];
up(Integer.MAX_VALUE, index);
poll();
return deleted;
}
/**
* 替换堆顶元素
*
* @param replaced 新元素
*/
public void replace(int replaced) {
array[0] = replaced;
down(0);
}
/**
* 堆的尾部添加元素
*
* @param offered 新元素
*/
public void offer(int offered) {
if (size == array.length) {
// 扩容
grow();
}
up(offered, size);
size++;
}
private void grow() {
int capacity = size + (size >> 1);
int[] newArray = new int[capacity];
System.arraycopy(array, 0,
newArray, 0, size);
array = newArray;
}
// 将 offered 元素上浮: 直至 offered 小于父元素或到堆顶
private void up(int offered, int index) {
int child = index;
while (child > 0) {
int parent = (child - 1) / 2;
boolean cmp = max ? offered > array[parent] : offered < array[parent];
if (cmp) {
array[child] = array[parent];
} else {
break;
}
child = parent;
}
array[child] = offered;
}
public Heap(int[] array, boolean max) {
this.array = array;
this.size = array.length;
this.max = max;
heapify();
}
// 建堆
private void heapify() {
// 如何找到最后这个非叶子节点 size / 2 - 1
for (int i = size / 2 - 1; i >= 0; i--) {
down(i);
}
}
// 将 parent 索引处的元素下潜: 与两个孩子较大者交换, 直至没孩子或孩子没它大
private void down(int parent) {
int left = parent * 2 + 1;
int right = left + 1;
int maxOrMin = parent;
if (left < size && (max ? array[left] > array[maxOrMin] : array[left] < array[maxOrMin])) {
maxOrMin = left;
}
if (right < size && (max ? array[right] > array[maxOrMin] : array[right] < array[maxOrMin])) {
maxOrMin = right;
}
if (maxOrMin != parent) { // 找到了更大的孩子
swap(maxOrMin, parent);
down(maxOrMin);
}
}
// 交换两个索引处的元素
private void swap(int i, int j) {
int t = array[i];
array[i] = array[j];
array[j] = t;
}
/*
100
/ \
10 99
/ \ / \
5 6 98 97
/\ /\ /
1 2 3 4 96
100
/ \
96 99
/ \ / \
10 6 98 97
/\ /\
1 2 3 4
*/
public static void main(String[] args) {
Heap heap = new Heap(5, true); //100,10,99,5,6,98,97,1,2,3,4,96
heap.offer(100);
heap.offer(10);
heap.offer(99);
heap.offer(5);
heap.offer(6);
heap.offer(98);
heap.offer(97);
heap.offer(1);
heap.offer(2);
heap.offer(3);
heap.offer(4);
heap.offer(96);
System.out.println(Arrays.toString(heap.array));
System.out.println(heap.size);
System.out.println(heap.poll(3));
System.out.println(Arrays.toString(heap.array));
System.out.println(heap.size);
}
}
package com.datastructure;
import java.util.Arrays;
public class Leetcode295 {
/**
* 为了保证两边数据量的平衡
* <ul>
* <li>两边个数一样时,左边个数加一</li>
* <li>两边个数不一样时,右边个数加一</li>
* </ul>
* 但是, 随便一个数能直接加入吗?
* <ul>
* <li>左边个数加一时, 把新元素加在右边,弹出右边最小的加入左边</li>
* <li>右边个数加一时, 把新元素加在左边,弹出左边最小的加入右边</li>
* </ul>
*/
public void addNum(int num) {
if (left.size() == right.size()) {
right.offer(num);
left.offer(right.poll());
} else {
left.offer(num);
right.offer(left.poll());
}
}
private Heap left = new Heap(10, true);
private Heap right = new Heap(10, false);
@Override
public String toString() {
int size = left.size;
int[] left = new int[size];
for (int i = 0; i < left.length; i++) {
left[size - 1 - i] = this.left.array[i];
}
int[] right = Arrays.copyOf(this.right.array, this.right.size);
return Arrays.toString(left) + " <-> " + Arrays.toString(right);
}
/**
* <ul>
* <li>两边数据一致, 左右各取堆顶元素求平均</li>
* <li>左边多一个, 取左边堆顶元素</li>
* </ul>
*/
public double findMedian() {
if (left.size() == right.size()) {
return (left.peek() + right.peek()) / 2.0;
} else {
return left.peek();
}
}
public static void main(String[] args) {
Leetcode295 test = new Leetcode295();
test.addNum(1);
test.addNum(2);
test.addNum(3);
test.addNum(7);
test.addNum(8);
test.addNum(9);
System.out.println(test);
System.out.println(test.findMedian());
test.addNum(10);
System.out.println(test);
System.out.println(test.findMedian());
test.addNum(4);
System.out.println(test);
System.out.println(test.findMedian());
}
}
8.二叉树
遍历
遍历分为两种:
广度优先遍历:尽可能访问距离根最近的节点,也成为层序遍历
深度优先遍历:对于二叉树分为三种遍历方式:
前序遍历:根左右
中序遍历:左根右
后续遍历:左右根
递归实现
package com.datastructure;
public class TreeNode {
public TreeNode left;
public int val;
public TreeNode right;
public TreeNode(int val) {
this.val = val;
}
public TreeNode(TreeNode left, int val, TreeNode right) {
this.left = left;
this.val = val;
this.right = right;
}
@Override
public String toString(){
return String.valueOf(this.val);
}
public static void main(String[] args) {
TreeNode root=new TreeNode(new TreeNode(new TreeNode(4),2,null),1,new TreeNode(new TreeNode(5),3,new TreeNode(6)));
preOrder(root);
System.out.println();
inOrder(root);
System.out.println();
postOrder(root);
}
static void preOrder(TreeNode node){
if(node==null){
return ;
}
System.out.print(node.val+" ");
preOrder(node.left);
preOrder(node.right);
}
static void inOrder(TreeNode node){
if(node==null){
return ;
}
inOrder(node.left);
System.out.print(node.val+" ");
inOrder(node.right);
}
static void postOrder(TreeNode node){
if(node==null){
return ;
}
postOrder(node.left);
postOrder(node.right);
System.out.print(node.val+" ");
}
}
迭代实现
public class E03Leetcode145 {
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<TreeNode> stack = new LinkedList<>();
TreeNode curr = root; // 代表当前节点
TreeNode pop = null; // 最近一次弹栈的元素
List<Integer> result = new ArrayList<>();
while (!stack.isEmpty() || curr != null) {
if (curr != null) {
stack.push(curr);
// 待处理左子树
curr = curr.left;
} else {
TreeNode peek = stack.peek();
// 没有右子树
if (peek.right == null) {
pop = stack.pop();
result.add(pop.val);
}
// 右子树处理完成
else if (peek.right == pop) {
pop = stack.pop();
result.add(pop.val);
}
// 待处理右子树
else {
curr = peek.right;
}
}
}
return result;
}
public static void main(String[] args) {
TreeNode root = new TreeNode(
new TreeNode(new TreeNode(4), 2, new TreeNode(5)),
1,
new TreeNode(new TreeNode(6), 3, new TreeNode(7))
);
// System.out.println(new E03Leetcode145().postorderTraversal(root));
LinkedList<TreeNode> stack = new LinkedList<>();
TreeNode curr = root; // 代表当前节点
TreeNode pop = null; // 最近一次弹栈的元素
while (!stack.isEmpty() || curr != null) {
if (curr != null) {
stack.push(curr);
// 待处理左子树
colorPrintln("前:" + curr.val, 31);
curr = curr.left;
} else {
TreeNode peek = stack.peek();
// 没有右子树
if (peek.right == null) {
colorPrintln("中:" + peek.val, 36);
pop = stack.pop();
// colorPrintln("后:" + pop.val, 34);
}
// 右子树处理完成
else if (peek.right == pop) {
pop = stack.pop();
// colorPrintln("后:" + pop.val, 34);
}
// 待处理右子树
else {
colorPrintln("中:" + peek.val, 36);
curr = peek.right;
}
}
}
}
public static void colorPrintln(String origin, int color) {
System.out.printf("\033[%dm%s\033[0m%n", color, origin);
}
}
对称二叉树
public class LeetCode101 {
public static boolean isSymmetric(TreeNode root){
return check(root.left,root.right);
}
private static boolean check(TreeNode left, TreeNode right) {
if(left==null&&right==null){
return true;
}
if(right==null||left==null){
return false;
}
if(left.val!=right.val){
return false;
}
return check(left.left,right.right)&&check(left.right,right.left);
}
public static void main(String[] args) {
TreeNode root=new TreeNode(new TreeNode(new TreeNode(3),2,new TreeNode(4)),1,new TreeNode(new TreeNode(4),2,new TreeNode(3)));
System.out.println(isSymmetric(root));
}
}
最大深度解法一
public class Leetcode104 {
public static int maxDepth(TreeNode node){
if (node==null){
return 0;
}
if(node.left==null&&node.right==null){
return 1;
}
int d1=maxDepth(node.left);
int d2=maxDepth(node.right);
return Integer.max(d1,d2)+1;
}
public static void main(String[] args) {
TreeNode root=new TreeNode(new TreeNode(2),1,new TreeNode(3));
System.out.println(maxDepth(root));
}
}
public class Leetcodel04_2 {
public static int maxDepth(TreeNode root){
TreeNode curr=root;
TreeNode pop=null;
int max=0;
LinkedList<TreeNode> stack=new LinkedList<>();
while (curr!=null||!stack.isEmpty()){
if(curr!=null){
stack.push(curr);
int size=stack.size();
if(size>max){
max=size;
}
curr=curr.left;
}
else {
TreeNode peek=stack.peek();
if(peek.right==null||peek.right==pop){
pop=stack.pop();
}else {
curr=peek.right;
}
}
}
return max;
}
public static void main(String[] args) {
TreeNode root=new TreeNode(new TreeNode(2),1,new TreeNode(3));
System.out.println(maxDepth(root));
}
}
package com.datastructure;
import java.util.LinkedList;
import java.util.Queue;
public class Leetcode104_3 {
/*
思路:
1. 使用层序遍历, 层数即最大深度
*/
public static int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int depth = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode poll = queue.poll();
// System.out.print(poll.val + "\t");
if (poll.left != null) {
queue.offer(poll.left);
}
if (poll.right != null) {
queue.offer(poll.right);
}
}
// System.out.println();
depth ++;
}
return depth;
}
public static void main(String[] args) {
TreeNode root=new TreeNode(new TreeNode(2),1,new TreeNode(3));
System.out.println(maxDepth(root));
}
}
最小深度
public class Leetcode111 {
public static int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int depth = 0;
while (!queue.isEmpty()) {
int size = queue.size();
depth ++;
for (int i = 0; i < size; i++) {
TreeNode poll = queue.poll();
if (poll.left == null && poll.right == null) {
return depth;
}
if (poll.left != null) {
queue.offer(poll.left);
}
if (poll.right != null) {
queue.offer(poll.right);
}
}
}
return depth;
}
public static void main(String[] args) {
TreeNode root=new TreeNode(new TreeNode(2),1,new TreeNode(3));
System.out.println(minDepth(root));
}
}
public class Leetcode111_1 {
public static int minDepth(TreeNode node) {
if (node == null) {
return 0;
}
int d1 = minDepth(node.left); // 1
int d2 = minDepth(node.right); // 0
if (d2 == 0) { // 当右子树为null
return d1 + 1; // 返回左子树深度+1
}
if (d1 == 0) { // 当左子树为null
return d2 + 1; // 返回右子树深度+1
}
return Integer.min(d1, d2) + 1;
}
public static void main(String[] args) {
TreeNode root=new TreeNode(new TreeNode(2),1,new TreeNode(3));
System.out.println(minDepth(root));
}
}
翻转二叉树
public class Leetcode226 {
private static void fn(TreeNode node){
if(node==null){
return;
}
TreeNode t=node.left;
node.left=node.right;
node.right=t;
fn(node.left);
fn(node.right);
}
}
二叉搜索树
package com.datastructure;
public class BSTTree2 <K extends Comparable<K>,V>{
static class BSTNode<K,V>{
K key;
V value;
BSTNode<K,V> left;
BSTNode<K,V> right;
public BSTNode(K key) {
this.key = key;
}
public BSTNode(K key, V value) {
this.key = key;
this.value = value;
}
public BSTNode(K key, V value, BSTNode<K, V> left, BSTNode<K, V> right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
}
BSTNode<K,V> root;
public V get(K key){
BSTNode<K,V> p=root;
while (p!=null){
int result=key.compareTo(p.key);
if(result<0){
p=p.left;
}else if(result>0){
p=p.right;
}else{
return p.value;
}
}
return null;
}
}
package com.datastructure;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class BSTTree1 {
BSTNode root;
static class BSTNode{
int key;
Object value;
BSTNode left;
BSTNode right;
public BSTNode(int key){
this.key=key;
}
public BSTNode(int key,Object value){
this.key=key;
this.value=value;
}
public BSTNode(int key, Object value, BSTNode left, BSTNode right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
}
public Object get(int key){
BSTNode node=root;
while (node!=null){
if(key<node.key){
node=node.left;
}else if (node.key<key){
node=node.right;
}else{
return node.value;
}
}
return null;
}
public Object min(){
return min(root);
}
private Object min(BSTNode node){
if(node==null){
return null;
}
BSTNode p=node;
while (p.left!=null){
p=p.left;
}
return p.value;
}
public Object max(){
return max(root);
}
private Object max(BSTNode node){
if(node==null){
return null;
}
BSTNode p=node;
while (p.right!=null){
p=p.right;
}
return p.value;
}
public void put(int key, Object value) {
root = doPut(root, key, value);
}
private BSTNode doPut(BSTNode node,int key,Object value){
if(node==null){
return new BSTNode(key,value);
}
if(key< node.key){
node.left=doPut(node.left,key,value);
} else if (key> node.key) {
node.right=doPut(node.right,key,value);
}else {
node.value=value;
}
return node;
}
public Object predecessor(int key){
BSTNode p=root;
BSTNode ancestorFromLeft = null;
while (p!=null){
if(key<p.key){
p=p.left;
} else if (key>p.key) {
ancestorFromLeft=p;
p=p.right;
}else {
break;
}
}
if(p==null){
return null;
}
// 找到节点 情况1:节点有左子树,此时前任就是左子树的最大值
if (p.left != null) {
return max(p.left);
}
// 找到节点 情况2:节点没有左子树,若离它最近的、自左而来的祖先就是前任
return ancestorFromLeft != null ?
ancestorFromLeft.value : null;
}
public Object successor(int key){
BSTNode p=root;
BSTNode ancestorFromRight=null;
while (p!=null){
if(key<p.key){
ancestorFromRight=p;
p=p.left;
} else if (key>p.key) {
p=p.right;
}else {
break;
}
}
// 没找到节点
if (p == null) {
return null;
}
// 找到节点 情况1:节点有右子树,此时后任就是右子树的最小值
if (p.right != null) {
return min(p.right);
}
// 找到节点 情况2:节点没有右子树,若离它最近的、自右而来的祖先就是后任
return ancestorFromRight != null ?
ancestorFromRight.value : null;
}
/**
* <h3>根据关键字删除</h3>
*
* @param key 关键字
* @return 被删除关键字对应值
*/
// public Object remove(int key) {
// ArrayList<Object> result = new ArrayList<>(); // 保存被删除节点的值
// root = doRemove(root, key, result);
// return result.isEmpty() ? null : result.get(0);
// }
//
// /*
// 4
// / \
// 2 6
// / \
// 1 7
//
// node 起点
// 返回值 删剩下的孩子(找到) 或 null(没找到)
// */
// private BSTNode doRemove(BSTNode node, int key, ArrayList<Object> result) {
// if (node == null) {
// return null;
// }
// if (key < node.key) {
// node.left = doRemove(node.left, key, result);
// return node;
// }
// if (node.key < key) {
// node.right = doRemove(node.right, key, result);
// return node;
// }
// result.add(node.value);
// if (node.left == null) { // 情况1 - 只有右孩子
// return node.right;
// }
// if (node.right == null) { // 情况2 - 只有左孩子
// return node.left;
// }
// BSTNode s = node.right; // 情况3 - 有两个孩子
// while (s.left != null) {
// s = s.left;
// }
// s.right = doRemove(node.right, s.key, new ArrayList<>());
// s.left = node.left;
// return s;
// }
public Object remove(int key) {
BSTNode p = root;
BSTNode parent = null;
while (p != null) {
if (key < p.key) {
parent = p;
p = p.left;
} else if (p.key < key) {
parent = p;
p = p.right;
} else {
break;
}
}
if (p == null) {
return null;
}
// 删除操作
if (p.left == null) {
shift(parent, p, p.right); // 情况1
} else if (p.right == null) {
shift(parent, p, p.left); // 情况2
} else {
// 情况4
// 4.1 被删除节点找后继
BSTNode s = p.right;
BSTNode sParent = p; // 后继父亲
while (s.left != null) {
sParent = s;
s = s.left;
}
// 后继节点即为 s
if (sParent != p) { // 不相邻
// 4.2 删除和后继不相邻, 处理后继的后事
shift(sParent, s, s.right); // 不可能有左孩子
s.right = p.right;
}
// 4.3 后继取代被删除节点
shift(parent, p, s);
s.left = p.left;
}
return p.value;
}
/**
* 托孤方法
*
* @param parent 被删除节点的父亲
* @param deleted 被删除节点
* @param child 被顶上去的节点
*/
private void shift(BSTNode parent, BSTNode deleted, BSTNode child) {
if (parent == null) {
root = child;
} else if (deleted == parent.left) {
parent.left = child;
} else {
parent.right = child;
}
}
/*
4
/ \
2 6
/ \ / \
1 3 5 7
*/
// 找 < key 的所有 value
public List<Object> less(int key) { // key=6
ArrayList<Object> result = new ArrayList<>();
BSTNode p = root;
LinkedList<BSTNode> stack = new LinkedList<>();
while (p != null || !stack.isEmpty()) {
if (p != null) {
stack.push(p);
p = p.left;
} else {
BSTNode pop = stack.pop();
// 处理值
if (pop.key < key) {
result.add(pop.value);
} else {
break;
}
p = pop.right;
}
}
return result;
}
// 找 > key 的所有 value
public List<Object> greater(int key) {
/*ArrayList<Object> result = new ArrayList<>();
BSTNode p = root;
LinkedList<BSTNode> stack = new LinkedList<>();
while (p != null || !stack.isEmpty()) {
if (p != null) {
stack.push(p);
p = p.left;
} else {
BSTNode pop = stack.pop();
// 处理值
if (pop.key > key) {
result.add(pop.value);
}
p = pop.right;
}
}
return result;*/
ArrayList<Object> result = new ArrayList<>();
BSTNode p = root;
LinkedList<BSTNode> stack = new LinkedList<>();
while (p != null || !stack.isEmpty()) {
if (p != null) {
stack.push(p);
p = p.right;
} else {
BSTNode pop = stack.pop();
// 处理值
if (pop.key > key) {
result.add(pop.value);
} else {
break;
}
p = pop.left;
}
}
return result;
}
// 找 >= key1 且 <= key2 的所有值
public List<Object> between(int key1, int key2) {
ArrayList<Object> result = new ArrayList<>();
BSTNode p = root;
LinkedList<BSTNode> stack = new LinkedList<>();
while (p != null || !stack.isEmpty()) {
if (p != null) {
stack.push(p);
p = p.left;
} else {
BSTNode pop = stack.pop();
// 处理值
if (pop.key >= key1 && pop.key <= key2) {
result.add(pop.value);
} else if (pop.key > key2) {
break;
}
p = pop.right;
}
}
return result;
}
}
public class Leetcode701 {
public static TreeNode insertInfoBST(TreeNode node,int val){
if(node==null){
return new TreeNode(val);
}
if(val<node.val){
node.left=insertInfoBST(node.left,val);
} else if (val> node.val) {
node.right=insertInfoBST(node.right,val);
}
return node;
}
public static void main(String[] args) {
TreeNode root=new TreeNode(new TreeNode(null,2,new TreeNode(3)),5,new TreeNode(6));
insertInfoBST(root,1);
}
}
public class Leetcode98 {
public boolean isValidBST1(TreeNode node){
TreeNode p=node;
LinkedList<TreeNode> stack=new LinkedList<>();
long prev=Long.MIN_VALUE;
while (p!=null||!stack.isEmpty()){
if(p!=null){
stack.push(p);
p=p.left;
}else{
TreeNode pop=stack.pop();
// 处理值
// System.out.println("compare:" + prev + " " + pop.val);
if (prev >= pop.val) {
return false;
}
p=pop.right;
}
}
return true;
}
long prev=Long.MIN_VALUE;
public boolean isisValidBST2(TreeNode node){
if (node == null) {
return true;
}
boolean a=isisValidBST2(node.left);
if(!a){
return false;
}
if(prev>=node.val){
return false;
}
prev=node.val;
return isisValidBST2(node.right);
}
// 解法3. 中序遍历递归实现(局部变量记录 prev) 0ms
public boolean isValidBST3(TreeNode node) {
return doValid3(node, new AtomicLong(Long.MIN_VALUE));
}
private boolean doValid3(TreeNode node, AtomicLong prev) {
if (node == null) {
return true;
}
boolean a = doValid3(node.left, prev);
if (!a) {
return false;
}
if (prev.get() >= node.val) {
return false;
}
prev.set(node.val);
return doValid3(node.right, prev);
}
/*
能否只判断父亲比左孩子大,比右孩子小?
4
/ \
2 6
/ \
1 3
*/
/*
-∞ 4 +∞
/ \
-∞ 2 4 6 +∞
/ \
4 3 6 7 +∞
*/
// 解法4. 上下限递归实现 0ms
public static boolean isValidBST(TreeNode node) {
return doValid4(node, Long.MIN_VALUE, Long.MAX_VALUE);
}
private boolean doValid4(TreeNode node,long min,long max){
if(node==null){
return true;
}
if(node.val<=min||node.val>=max){
return false;
}
return doValid4(node.left,min, node.val)&&doValid4(node.right,node.val,max);
}
public static void main(String[] args) {
/*
4
/ \
2 6
/ \
1 3
*/
TreeNode root1 = new TreeNode(new TreeNode(new TreeNode(1),2,new TreeNode(3)),4,new TreeNode(6));
System.out.println(isValidBST(root1));
// System.out.println("---------------");
/*
4
/ \
2 6
/ \
3 7
*/
TreeNode root2 = new TreeNode(new TreeNode(2),4,new TreeNode(new TreeNode(3),6,new TreeNode(7)));
System.out.println(isValidBST(root2));
// System.out.println("---------------");
/*
1
/
1
*/
TreeNode root3 = new TreeNode(new TreeNode(1),1,null);
System.out.println(isValidBST(root3));
// System.out.println("---------------");
/*
3
\
4
/
5
*/
TreeNode root4 = new TreeNode(null,3,new TreeNode(new TreeNode(5),4,null));
System.out.println(isValidBST(root4));
}
}
public class Leetcode938 {
public static int rangeSumBST(TreeNode node, int low, int high){
if(node==null){
return 0;
}
if(node.val<low){
return rangeSumBST(node.right, low,high);
}
if(node.val>high){
return rangeSumBST(node.left,low,high);
}
return node.val+rangeSumBST(node.left,low,high)+rangeSumBST(node.right,low,high);
}
public static int rangeSumBST1(TreeNode node, int low, int high){
TreeNode p=node;
LinkedList<TreeNode>stack=new LinkedList<>();
int sum=0;
while (p!=null||!stack.isEmpty()){
if(p!=null){
stack.push(p);
p=p.left;
}else {
TreeNode pop=stack.pop();
if(pop.val>high){
break;
}
if(pop.val>=low){
sum+= pop.val;
}
p=pop.right;
}
}
return sum;
}
public static void main(String[] args) {
/*
10
/ \
5 15
/ \ \
3 7 18 low=7 high=15
*/
TreeNode n1 = new TreeNode(new TreeNode(new TreeNode(3),5,new TreeNode(7)),10,new TreeNode(null,15,new TreeNode(18)));
int sum = rangeSumBST1(n1, 7, 15);
System.out.println(sum); // 应为 32
}
}
根据前序遍历结果建树
public class Leetcode1008 {
public static TreeNode bstFromPreorder(int[] preorder) {
TreeNode root=insert(null,preorder[0]);
for (int i = 1; i < preorder.length; i++) {
insert(root,preorder[i]);
}
return root;
}
private static TreeNode insert(TreeNode node,int val){
if (node==null){
return new TreeNode(val);
}
if(val<node.val){
node.left=insert(node.left,val);
}else if(node.val<val){
node.right=insert(node.right,val);
}
return node;
}
public static void main(String[] args) {
int a[]={8,5,1,7,10,12};
TreeNode t1=bstFromPreorder(a);
TreeNode t=new TreeNode(new TreeNode(new TreeNode(1),5,new TreeNode(7)),8,new TreeNode(null,10,new TreeNode(12)));
System.out.println(isSameTree(t1,t));
}
public static boolean isSameTree(TreeNode t1,TreeNode t2){
if(t1==null&&t2==null){
return true;
}
if (t1==null){
return false;
}
if(t2==null){
return false;
}
return isSameTree(t1.left,t2.left)&&isSameTree(t2.right,t2.right);
}
}
最近公共祖先(祖先也包括自己)
public class Leetcode235 {
/*
__ 6 __
/ \
2 8
/ \ / \
0 4 7 9
/ \
3 5
待查找节点 p q 在某一节点的两侧,那么此节点就是最近的公共祖先
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
TreeNode a = root;
while (p.val < a.val && q.val < a.val || a.val < p.val && a.val < q.val) { // 在同一侧
if (p.val < a.val) {
a = a.left;
} else {
a = a.right;
}
}
return a;
}
public static void main(String[] args) {
TreeNode root=new TreeNode(new TreeNode(new TreeNode(0),2,new TreeNode(new TreeNode(3),4,new TreeNode(5))),6,new TreeNode(new TreeNode(7),8,new TreeNode(9)));
TreeNode t1 = new Leetcode235().lowestCommonAncestor(root, new TreeNode(2), new TreeNode(8));
System.out.println(t1.val); // 应为 6
TreeNode t2 = new Leetcode235().lowestCommonAncestor(root, new TreeNode(4), new TreeNode(5));
System.out.println(t2.val); // 应为 4
}
}
AVL树
public class AVLTree {
/**
* <h3>AVL 树</h3>
* <ul>
* <li>二叉搜索树在插入和删除时,节点可能失衡</li>
* <li>如果在插入和删除时通过旋转, 始终让二叉搜索树保持平衡, 称为自平衡的二叉搜索树</li>
* <li>AVL 是自平衡二叉搜索树的实现之一</li>
* </ul>
*/
static class AVLNode{
int key;
Object value;
AVLNode left;
AVLNode right;
int height=1;
public AVLNode(int key, Object value) {
this.key = key;
this.value = value;
}
public AVLNode(int key) {
this.key = key;
}
public AVLNode(int key, Object value, AVLNode left, AVLNode right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
}
private int height(AVLNode node){
return node==null?0: node.height;
}
private void updateHeight(AVLNode node){
node.height = Integer.max(height(node.left), height(node.right)) + 1;
}
private int bf(AVLNode node) {
return height(node.left) - height(node.right);
}
// 参数:要旋转的节点, 返回值:新的根节点
private AVLNode rightRotate(AVLNode red) {
AVLNode yellow = red.left;
AVLNode green = yellow.right;
yellow.right = red; // 上位
red.left = green; // 换爹
updateHeight(red);
updateHeight(yellow);
return yellow;
}
// 参数:要旋转的节点, 返回值:新的根节点
private AVLNode leftRotate(AVLNode red) {
AVLNode yellow = red.right;
AVLNode green = yellow.left;
yellow.left = red;
red.right = green;
updateHeight(red);
updateHeight(yellow);
return yellow;
}
// 先左旋左子树, 再右旋根节点
private AVLNode leftRightRotate(AVLNode node) {
node.left = leftRotate(node.left);
return rightRotate(node);
}
// 先右旋右子树, 再左旋根节点
private AVLNode rightLeftRotate(AVLNode node) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
// 检查节点是否失衡, 重新平衡代码
private AVLNode balance(AVLNode node) {
if (node == null) {
return null;
}
int bf = bf(node);
if (bf > 1 && bf(node.left) >= 0) { // LL
return rightRotate(node);
} else if (bf > 1 && bf(node.left) < 0) { // LR
return leftRightRotate(node);
} else if (bf < -1 && bf(node.right) > 0) { // RL
return rightLeftRotate(node);
} else if (bf < -1 && bf(node.right) <= 0) { // RR
return leftRotate(node);
}
return node;
}
AVLNode root;
public void put(int key, Object value) {
root = doPut(root, key, value);
}
private AVLNode doPut(AVLNode node, int key, Object value) {
// 1. 找到空位, 创建新节点
if (node == null) {
return new AVLNode(key, value);
}
// 2. key 已存在, 更新
if (key == node.key) {
node.value = value;
return node;
}
// 3. 继续查找
if (key < node.key) {
node.left = doPut(node.left, key, value); // 向左
} else {
node.right = doPut(node.right, key, value); // 向右
}
updateHeight(node);
return balance(node);
}
public void remove(int key) {
root = doRemove(root, key);
}
private AVLNode doRemove(AVLNode node, int key) {
// 1. node == null
if (node == null) {
return null;
}
// 2. 没找到 key
if (key < node.key) {
node.left = doRemove(node.left, key);
} else if (node.key < key) {
node.right = doRemove(node.right, key);
} else {
// 3. 找到 key 1) 没有孩子 2) 只有一个孩子 3) 有两个孩子
if (node.left == null && node.right == null) {
return null;
} else if (node.left == null) {
node = node.right;
} else if (node.right == null) {
node = node.left;
} else {
AVLNode s = node.right;
while (s.left != null) {
s = s.left;
}
// s 后继节点
s.right = doRemove(node.right, s.key);
s.left = node.left;
node = s;
}
}
// 4. 更新高度
updateHeight(node);
// 5. balance
return balance(node);
}
}
红黑树
红黑树特性
- 所有节点都有两种颜色:红与黑
- 所有null视为黑色
- 红色节点不能相邻
- 根节点是黑色
- 从根到任意一个叶子节点,路径中的黑色节点数一样(黑色完美平衡)
删黑色会失衡,删红色不会失衡,但删黑色有一种简单情况
删的是黑,剩下的是红色,剩下的这个红节点变黑
import static com.datastructure.RedBlackTree.Color.BLACK;
import static com.datastructure.RedBlackTree.Color.RED;
public class RedBlackTree {
enum Color {
RED, BLACK;
}
Node root;
static class Node {
int key;
Object value;
Node left;
Node right;
Node parent; // 父节点
Color color = RED; // 颜色
public Node(int key, Object value) {
this.key = key;
this.value = value;
}
public Node(int key) {
this.key = key;
}
public Node(int key, Color color) {
this.key = key;
this.color = color;
}
public Node(int key, Color color, Node left, Node right) {
this.key = key;
this.color = color;
this.left = left;
this.right = right;
if (left != null) {
left.parent = this;
}
if (right != null) {
right.parent = this;
}
}
// 是否是左孩子
boolean isLeftChild() {
return parent != null && parent.left == this;
}
// 叔叔
Node uncle() {
if (parent == null || parent.parent == null) {
return null;
}
if (parent.isLeftChild()) {
return parent.parent.right;
} else {
return parent.parent.left;
}
}
// 兄弟
Node sibling() {
if (parent == null) {
return null;
}
if (this.isLeftChild()) {
return parent.right;
} else {
return parent.left;
}
}
}
// 判断红
boolean isRed(Node node) {
return node != null && node.color == RED;
}
// 判断黑
boolean isBlack(Node node) {
// return !isRed(node);
return node == null || node.color == BLACK;
}
// 右旋 1. parent 的处理 2. 旋转后新根的父子关系
private void rightRotate(Node pink) {
Node parent = pink.parent;
Node yellow = pink.left;
Node green = yellow.right;
if (green != null) {
green.parent = pink;
}
yellow.right = pink;
yellow.parent = parent;
pink.left = green;
pink.parent = yellow;
if (parent == null) {
root = yellow;
} else if (parent.left == pink) {
parent.left = yellow;
} else {
parent.right = yellow;
}
}
// 左旋
private void leftRotate(Node pink) {
Node parent = pink.parent;
Node yellow = pink.right;
Node green = yellow.left;
if (green != null) {
green.parent = pink;
}
yellow.left = pink;
yellow.parent = parent;
pink.right = green;
pink.parent = yellow;
if (parent == null) {
root = yellow;
} else if (parent.left == pink) {
parent.left = yellow;
} else {
parent.right = yellow;
}
}
/**
* 新增或更新
* <br>
* 正常增、遇到红红不平衡进行调整
*
* @param key 键
* @param value 值
*/
public void put(int key, Object value) {
Node p = root;
Node parent = null;
while (p != null) {
parent = p;
if (key < p.key) {
p = p.left;
} else if (p.key < key) {
p = p.right;
} else {
p.value = value; // 更新
return;
}
}
Node inserted = new Node(key, value);
if (parent == null) {
root = inserted;
} else if (key < parent.key) {
parent.left = inserted;
inserted.parent = parent;
} else {
parent.right = inserted;
inserted.parent = parent;
}
fixRedRed(inserted);
}
void fixRedRed(Node x) {
// case 1 插入节点是根节点,变黑即可
if (x == root) {
x.color = BLACK;
return;
}
// case 2 插入节点父亲是黑色,无需调整
if (isBlack(x.parent)) {
return;
}
/* case 3 当红红相邻,叔叔为红时
需要将父亲、叔叔变黑、祖父变红,然后对祖父做递归处理
*/
Node parent = x.parent;
Node uncle = x.uncle();
Node grandparent = parent.parent;
if (isRed(uncle)) {
parent.color = BLACK;
uncle.color = BLACK;
grandparent.color = RED;
fixRedRed(grandparent);
return;
}
// case 4 当红红相邻,叔叔为黑时
if (parent.isLeftChild() && x.isLeftChild()) { // LL
parent.color = BLACK;
grandparent.color = RED;
rightRotate(grandparent);
} else if (parent.isLeftChild()) { // LR
leftRotate(parent);
x.color = BLACK;
grandparent.color = RED;
rightRotate(grandparent);
} else if (!x.isLeftChild()) { // RR
parent.color = BLACK;
grandparent.color = RED;
leftRotate(grandparent);
} else { // RL
rightRotate(parent);
x.color = BLACK;
grandparent.color = RED;
leftRotate(grandparent);
}
}
/**
* 删除
* <br>
* 正常删、会用到李代桃僵技巧、遇到黑黑不平衡进行调整
*
* @param key 键
*/
public void remove(int key) {
Node deleted = find(key);
if (deleted == null) {
return;
}
doRemove(deleted);
}
public boolean contains(int key) {
return find(key) != null;
}
// 查找删除节点
private Node find(int key) {
Node p = root;
while (p != null) {
if (key < p.key) {
p = p.left;
} else if (p.key < key) {
p = p.right;
} else {
return p;
}
}
return null;
}
// 查找剩余节点
private Node findReplaced(Node deleted) {
if (deleted.left == null && deleted.right == null) {
return null;
}
if (deleted.left == null) {
return deleted.right;
}
if (deleted.right == null) {
return deleted.left;
}
Node s = deleted.right;
while (s.left != null) {
s = s.left;
}
return s;
}
// 处理双黑 (case3、case4、case5)
private void fixDoubleBlack(Node x) {
if (x == root) {
return;
}
Node parent = x.parent;
Node sibling = x.sibling();
// case 3 兄弟节点是红色
if (isRed(sibling)) {
if (x.isLeftChild()) {
leftRotate(parent);
} else {
rightRotate(parent);
}
parent.color = RED;
sibling.color = BLACK;
fixDoubleBlack(x);
return;
}
if (sibling != null) {
// case 4 兄弟是黑色, 两个侄子也是黑色
if (isBlack(sibling.left) && isBlack(sibling.right)) {
sibling.color = RED;
if (isRed(parent)) {
parent.color = BLACK;
} else {
fixDoubleBlack(parent);
}
}
// case 5 兄弟是黑色, 侄子有红色
else {
// LL
if (sibling.isLeftChild() && isRed(sibling.left)) {
rightRotate(parent);
sibling.left.color = BLACK;
sibling.color = parent.color;
}
// LR
else if (sibling.isLeftChild() && isRed(sibling.right)) {
sibling.right.color = parent.color;
leftRotate(sibling);
rightRotate(parent);
}
// RL
else if (!sibling.isLeftChild() && isRed(sibling.left)) {
sibling.left.color = parent.color;
rightRotate(sibling);
leftRotate(parent);
}
// RR
else {
leftRotate(parent);
sibling.right.color = BLACK;
sibling.color = parent.color;
}
parent.color = BLACK;
}
} else {
// @TODO 实际也不会出现,触发双黑后,兄弟节点不会为 null
fixDoubleBlack(parent);
}
}
private void doRemove(Node deleted) {
Node replaced = findReplaced(deleted);
Node parent = deleted.parent;
// 没有孩子
if (replaced == null) {
// case 1 删除的是根节点
if (deleted == root) {
root = null;
} else {
if (isBlack(deleted)) {
// 复杂调整
fixDoubleBlack(deleted);
} else {
// 红色叶子, 无需任何处理
}
if (deleted.isLeftChild()) {
parent.left = null;
} else {
parent.right = null;
}
deleted.parent = null;
}
return;
}
// 有一个孩子
if (deleted.left == null || deleted.right == null) {
// case 1 删除的是根节点
if (deleted == root) {
root.key = replaced.key;
root.value = replaced.value;
root.left = root.right = null;
} else {
if (deleted.isLeftChild()) {
parent.left = replaced;
} else {
parent.right = replaced;
}
replaced.parent = parent;
deleted.left = deleted.right = deleted.parent = null;
if (isBlack(deleted) && isBlack(replaced)) {
// 复杂处理 @TODO 实际不会有这种情况 因为只有一个孩子时 被删除节点是黑色 那么剩余节点只能是红色不会触发双黑
fixDoubleBlack(replaced);
} else {
// case 2 删除是黑,剩下是红
replaced.color = BLACK;
}
}
return;
}
// case 0 有两个孩子 => 有一个孩子 或 没有孩子
int t = deleted.key;
deleted.key = replaced.key;
replaced.key = t;
Object v = deleted.value;
deleted.value = replaced.value;
replaced.value = v;
doRemove(replaced);
}
}