数据结构与算法(上)

目录

1.二分查找

2.数组 

3.链表

4.递归

5.队列

6.栈

7.堆

8.二叉树

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("---------------");
    }
}

时间复杂度

T(n)=c(2^{n}-1) 

 杨辉三角

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);
    }
}

 红黑树

红黑树特性

  1. 所有节点都有两种颜色:红与黑
  2. 所有null视为黑色
  3. 红色节点不能相邻
  4. 根节点是黑色
  5. 从根到任意一个叶子节点,路径中的黑色节点数一样(黑色完美平衡)

删黑色会失衡,删红色不会失衡,但删黑色有一种简单情况

删的是黑,剩下的是红色,剩下的这个红节点变黑

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);
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值