算法总结

技巧

鸽舍原理
如果每个抽屉代表一个集合,每一个苹果就可以代表一个元素,假如有 n+1或多于n+1个元素放到n个集合中去,其中必定至少有一个集合里至少有两个元素。
求中值索引避免越界:int mid = L + ((R - L) >> 1)
java中负数2进制以补码形式展示,10进制转换2进制,正数部分%2取反,小数部分*2.
n的子集->2的n次方
n的排列->n!
奇偶判断:(n&1)==1,为奇数
判断两个数字符号是否相等:((a >> 31) ^ (b >> 31)) == 0
优先级:单目乘除位关系,逻辑三目后赋值。
&&和||:具有短路特点
图的连通:DFS、BFS、UNION-FIND
查找排序算法效率比较?

算法

  1. 问题理解
  2. exact、approximation,数据结构
  3. 算法描述–伪代码
  4. 算法正确性证明
  5. 算法分析–时间空间效率

效率分析

  1. 输入规模度量
  2. 基本操作次数统计(对数级增长最慢)
  3. 最优、最差及平均效率

数值交换
寄存法,a与b交换,可能出现溢出
a=a+b
b=a-b
a=a-b
异或法,由a^a=0,a^0=a可以得出,a与b交换,a=a^a^b,b=b^b^a
a=a^b
b=a^b
a=a^b

数组左移、右移k位
颠倒数组,颠倒0~k位,颠倒k+1~n位
找出数组中只出现一次的元素
其余元素出现两次,遍历数组,num[i]^num[i+1]
1.欧几里得算法求最大公约数
(m,n)->(n,m%n)->(x,0)->x为最大公约数
最小公倍数=a*b/gcd(a,b)

public static int gcd(int m, int n){
        while(n!=0){
            int interim = m%n;
            m=n;
            n=interim;
        }
        return m;
}

2.埃拉托色尼筛选法
求不大于n的质数序列,消除从p*p~n

public static int[] sieve(int n){
        //记录被消除个数
        int count=0;
        int[] nums = new int[n];
        for(int i=2;i<=Math.sqrt(n);i++){
            if(nums[i]==0){
                for(int j=i*i;j<n;j+=i){
                    if(nums[j]==0){
                        nums[j]=1;
                        count++;
                    }
                }
            }
        }
        int[] result = new int[n-count-2];
        count=0;
        for(int i=2;i<n;i++){
            if(nums[i]==0){
                result[count++]=i;
            }
        }
        return result;
}

蛮力法
3.选择排序—循环一次选择最大或最小交换
4.冒泡排序—比较并交换,一次循环确定最大或最小
5.顺序查找
可以选择将查找元素插入列表,避免每次判断是否到列表尾。
6.蛮力匹配字符串

public static String stringMatch(String str,String pattern){
        String result="";
        for(int i=0;i<str.length()-pattern.length();i++){
            int j=0;
            while(j<pattern.length()){
                if(str.charAt(i+j)!=pattern.charAt(j)){
                    break;
                }
                j++;
            }
            if(j==pattern.length()){
                return result+str.substring(i,i+j)+"-location:"+i+"~"+(i+j);
            }
        }
        return result;
    }

7.最近点对

    //最近点对问题
    public static void closestPair(int[][] points){
        double distance = Double.MAX_VALUE;
        int pointx=0,pointy=0;
        for(int i=0;i<points.length;i++){
            for(int j=i+1;j<points.length;j++){
                double curDistance=Math.pow((points[i][0]-points[j][0]),2)+Math.pow((points[i][1]-points[j][1]),2);
                if(curDistance<distance){
                    distance=curDistance;
                    pointx=i;
                    pointy=j;
                }
            }
        }
        System.out.println("最近点对为:(" + points[pointx][0] + "," + points[pointx][1] + ")--(" + points[pointy][0] + "," + points[pointy][1] + ")");
    }

8.凸包问题

//凸包问题
    public static void convexHull(int[][] points){
        Set<Integer> set = new HashSet<Integer>();
        for(int i=0;i<points.length;i++){
            for(int j=i+1;j<points.length;j++){
                //a=y2-y1,b=x1-x2,c=x1y2-x2y1,ax+by=c
                int a=points[j][1]-points[i][1],b=points[i][0]-points[j][0],c=points[i][0]*points[j][1]-points[j][0]*points[i][1];
                int judge=-1;
                int k=0;
                for(;k<points.length;k++){
                    //ax+by>c
                    if(a*points[k][0]+b*points[k][1]>c){
                        if(judge==-1){
                            judge=0;
                        }else if(judge==1){
                            break;
                        }
                    }else if(a*points[k][0]+b*points[k][1]<c){
                        if(judge==-1){
                            judge=1;
                        }else if(judge==0){
                            break;
                        }
                    }
                }
                //满足凸点线段
                if(k==points.length){
                    set.add(i);
                    set.add(j);
                }
            }
        }
        System.out.println("凸点集合如下");
        for(Integer point:set){
            System.out.println("("+points[point][0]+","+points[point][1]+")");
        }
    }

生成数的排列

    //判断交换元素之间是否存在重复元素
    public static boolean judgeRepeat(int[] nums,int index,int repeat){
        for(int i=index;i<repeat;i++){
            if(nums[i]==nums[repeat]) {
                return false;
            }
        }
        return true;
    }
    //求排列--递归
    public static void permutation1(int[] nums,int index){
        if(index==nums.length){
            System.out.println(Arrays.toString(nums));
            count++;
            return;
        }
        for(int i=index;i<nums.length;i++){
            if(judgeRepeat(nums,index,i)) {
                //交换
                if(i!=index) {
                    nums[index] ^= nums[i];
                    nums[i] ^= nums[index];
                    nums[index] ^= nums[i];
                }
            permutation1(nums,index+1);
                //复位
                if(i!=index) {
                    nums[index] ^= nums[i];
                    nums[i] ^= nums[index];
                    nums[index] ^= nums[i];
                }
            }
        }
    }
//求排列--字典序
    public static void permutation2(int[] nums){
        Arrays.sort(nums);
        while(nextPermutate(nums)){
            System.out.println(Arrays.toString(nums));
            count++;
        }

    }
    public static boolean nextPermutate(int[] nums){
        int point1=nums.length-1,point2=nums.length-1;
        while(point1>0&&nums[point1]<=nums[point1-1]){
            point1--;
        }
        //未找到递增序列
        if(point1==0){
            return false;
        }else{
            //存在递增序列就必定存在point2>point1-1的数
            while(nums[point2]<=nums[point1-1]){
                point2--;
            }
            //交换point1和point2
            nums[point1-1]^=nums[point2];
            nums[point2]^=nums[point1-1];
            nums[point1-1]^=nums[point2];
            //颠倒从point1到数组末尾的所有数
            for(int i=point1,j=nums.length-1;i<j;i++,j--){
                nums[i]^=nums[j];
                nums[j]^=nums[i];
                nums[i]^=nums[j];
            }
            return true;
        }
    }

生成数的组合

//求组合 参数:数组,当前递归层数,组合数,遍历数组开始索引,不能解决存在重复元素
    public static void combination(int[] nums,int index,int number,int begin){
        if(index==number){
            for(int i=0;i<number;i++){
                System.out.print(nums[i]+" ");
            }
            System.out.println();
            count++;
            return ;
        }
        for(int i=begin;i<nums.length;i++){
            if(judgeRepeat(nums,index,i)) {
                //交换
                if (i != begin) {
                    nums[i] ^= nums[index];
                    nums[index] ^= nums[i];
                    nums[i] ^= nums[index];
                }
                combination(nums, index + 1, number, i + 1);
                //复位
                if (i != begin) {
                    nums[i] ^= nums[index];
                    nums[index] ^= nums[i];
                    nums[i] ^= nums[index];
                }
            }
        }
    }

生成数的子集

//求子集,不能解决存在重复元素
    public static void subset1(int[] nums){
        ArrayList<ArrayList<String>> result = new ArrayList<>();
        //result初始要有一个空集
        result.add(new ArrayList<>());
        for(int i=0;i<nums.length;i++) {
            //将当前元素与之前所有元素拼接形成新集合
            for (int j = result.size() - 1; j >= 0; j--) {
                ArrayList<String> list = new ArrayList<>(result.get(j));
                list.add(String.valueOf(nums[i]));
                result.add(list);
            }
        }
        for(int i=0;i<result.size();i++){
            System.out.println(Arrays.toString(result.get(i).toArray()));
        }
    }
//求子集---2进制方式,不能解决存在重复元素
    public static void subset2(int[] nums){
        long max=1<<nums.length;
        ArrayList<ArrayList<String>> result =new ArrayList<>();
        while(max>0){
            ArrayList<String> list = new ArrayList<>();
            long interim=max-1;
            int index=0;
            while(interim>0){
                if((interim&1)>0){
                    list.add(String.valueOf(nums[index]));
                }
                interim>>=1;
                index++;
            }
            result.add(list);
            max--;
        }
        for(int i=0;i<result.size();i++){
            System.out.println(Arrays.toString(result.get(i).toArray()));
        }
    }

旅行商问题
背包问题
分配问题

减治法

减常量
减系数因子
减规模

插入排序—对基本有序数组效率高
拓扑排序

 //拓扑排序,减治法
    public static void topologicalSort(int[][] matrix){
        ArrayList<Integer> topological = new ArrayList<>();
        //构建入度表
        int[] indegree = new int[matrix.length];
        for(int j=0;j<indegree.length;j++){
            for(int i=0;i<indegree.length;i++){
                if(matrix[i][j]!=0){
                    indegree[j]++;
                }
            }
        }
        LinkedList<Integer> queue= new LinkedList<>();
        //将入度为零的节点加入队列
        for(int i=0;i<indegree.length;i++){
            if(indegree[i]==0){
                queue.offer(i);
            }
        }
        //将入度表为零的节点指向的节点入度减一
        while(!queue.isEmpty()){
            Integer node = queue.poll();
            topological.add(node);
            for(int i=0;i<indegree.length;i++){
                if(matrix[node][i]!=0){
                    indegree[i]--;
                    if(indegree[i]==0){
                        queue.offer(i);
                    }
                }
            }
        }
        if(topological.size()!=indegree.length){
            System.out.println("邻接矩阵中存在有向环不能进行拓扑排序!");
        }else{
            System.out.println("邻接矩阵拓扑排序为:"+Arrays.toString(topological.toArray()));
        }
    }
//拓扑排序,深度优先,通过标记数组控制
    public static void topologicalSort2(int[][] matrix){
        //标记数组
        int[] flag = new int[matrix.length];
        ArrayList<Integer> topological = new ArrayList<>();
        //遍历每个节点
        for(int i=0;i<flag.length;i++){
            if(!topologicalDFS(matrix,flag,i,topological)){
                System.out.println("邻接矩阵中存在有向环不能进行拓扑排序!");
                return;
            }
        }
        //颠倒
        Collections.reverse(topological);
        //遍历完成,显示拓扑排序
        System.out.println("邻接矩阵拓扑排序为:"+Arrays.toString(topological.toArray()));
    }
    public static boolean topologicalDFS(int[][] matrix,int[] flag,int node,ArrayList<Integer> result){
        //当前节点在当前递归中已经被访问过,表示存在回路
        if(flag[node]==1){
            return false;
        }
        //当前节点在其他节点递归中已经访问过,不再添加
        if(flag[node]==-1){
            return true;
        }
        flag[node]=1;
        for(int i=0;i<flag.length;i++){
            if(matrix[node][i]==1&&!topologicalDFS(matrix,flag,i,result)){
                return false;
            }
        }
        //当前节点循环结束,将节点加入拓扑排序中
        result.add(node);
        flag[node]=-1;
        return true;
    }

假币问题
俄罗斯乘法–用移位和加法处理

//俄罗斯乘法
    public static int multiplication(int n,int m){
        //n*m=n/2*2m 偶数,n*m=(n-1)/2*2m+m 奇数
        int result=0;
        while(n>0){
            if((n&1)==1){
                result+=m;
            }
            n>>=1;
            m<<=1;
        }
        return result;
    }

约瑟夫问题

//约瑟夫问题,排成一圈为m的去除
    public static int joseph(int n,int m){
        //公式f(n)=(f(n-1)+m-1)%n+1
        int result=1;
        for(int i=1;i<n;i++){
            result=(result+m-1)%(i+1)+1;
        }
        return result;
    }

减规模
求第k个最小元素

//利用快排思想找数组第k小的元素
    public static int findMin(int[] nums,int k){
        int left=0,right=nums.length-1;
        int p=partition(nums,left,right);
        while(p+1!=k){
            if(p+1>k){
                p=partition(nums,left,p-1);
            }else{
                p=partition(nums,p+1,right);
            }
        }
        return nums[p];
    }
    public static int partition(int[]nums,int left,int right){
        int count=left;
        for(int i=left+1;i<=right;i++){
            if(nums[i]<nums[count]){
                nums[count]^=nums[i];
                nums[i]^=nums[count];
                nums[count]^=nums[i];
                count=i;
            }
        }
        return count;
    }

插值查找
相比折半查找在大规模数据查找可能更好

//插值查找,利用两点式直线方程查找键值位置
    public static int insertSearch(int[]nums,int value){
        int left=0,right=nums.length-1;
        //x=x1+[(v-y1)*(x2-x1)/(y2-y1)]
        while(left<right){
            int x=left+(int)Math.floor((value-nums[left])*(right-left)/(nums[right]-nums[left]));
            if(x>right){
                return -1;
            }else if(nums[x]==value){
                return x;
            }else if(nums[x]>value){
                right=x-1;
            }else{
                left=x+1;
            }
        }
        return -1;
    }

分治法

T(n)=aT(n/b)+f(n):分治时间效率=每个子问题求解花费时间+分解和合并子问题所花时间
合并排序
快速排序
大整数加减乘除

    //大数加法
    public static String bigDigitAdd(String var1,String var2){
        if(var1==null||var2==null||var1.length()<1||var2.length()<1){
            return null;
        }
        int carry=0;
        StringBuilder sb = new StringBuilder();
        int index1=var1.length()-1,index2=var2.length()-1;
        for(;index1>=0||index2>=0;index1--,index2--){
            int interim=carry;
            interim=index1>=0?interim+var1.charAt(index1)-48:interim;
            interim=index2>=0?interim+var2.charAt(index2)-48:interim;
            if(interim>9){
                carry=1;
                sb.append((interim-10));
            }else{
                sb.append(interim);
                carry=0;
            }
        }
        if(carry==1){
            sb.append(1);
        }
        return sb.reverse().toString();
    }
    //大数减法
    public static String bigDigitSubtract(String var1,String var2){
        if(var1==null||var2==null||var1.length()<1||var2.length()<1){
            return null;
        }
        String max=var1.length()>=var2.length()?var1:var2;
        String min=var1.length()<var2.length()?var1:var2;
        int covering=0;
        int index1=max.length()-1,index2=min.length()-1;
        StringBuilder sb = new StringBuilder();
        for(;index1>=0||index2>=0;index1--,index2--){
            int interim=max.charAt(index1)-covering-48;
            interim=index2>=0?interim-min.charAt(index2)+48:interim;
            if(interim<0){
                covering=1;
                sb.append(interim+10);
            }else{
                if(index1==0&&interim==0){
                    break;
                }
                covering=0;
                sb.append(interim);
            }
        }
        return sb.reverse().toString();
    }
    //大数乘法,ab*cd=a*c+(a+b)*(c+d)-(a*c+b*d)+b*d,ac指数为2m,中间为m
    public static String bigDigitMultiply(String var1,String var2){
        if(var1==null||var2==null||var1.length()<1||var2.length()<1){
            return null;
        }
        int len1=var1.length();
        int len2=var2.length();
        int maxLen=Math.max(len1,len2);
        if(maxLen<4){
            return String.valueOf(Integer.parseInt(var1)*Integer.parseInt(var2));
        }
        StringBuilder c1= new StringBuilder();
        StringBuilder c2= new StringBuilder();
        while(len1++<maxLen){
            c1.append('0');
        }
        c1.append(var1);
        while(len2++<maxLen){
            c2.append('0');
        }
        c2.append(var2);
        int mid = maxLen/2;
        String AC=bigDigitMultiply(c1.substring(0,mid),c2.substring(0,mid));
        String BD=bigDigitMultiply(c1.substring(mid),c2.substring(mid));
        String ABCD=bigDigitMultiply(bigDigitAdd(c1.substring(0,mid),c1.substring(mid)),bigDigitAdd(c2.substring(0,mid),c2.substring(mid)));
        String ACBD=bigDigitSubtract(ABCD,bigDigitAdd(AC,BD));
        int carry1=(maxLen-mid)*2;
        int carry2=maxLen-mid;
        while(carry1-->0){
            AC+="0";
        }
        while(carry2-->0){
            ACBD+="0";
        }
        return bigDigitAdd(AC,bigDigitAdd(BD,ACBD));
    }
    //大数除法,对应位数相减
    public static boolean compareStr(String var1,String var2){
        if(var1.length()<var2.length()){
            return false;
        }else if(var1.length()==var2.length()){
            return var1.compareTo(var2) >= 0;
        }else{
            return true;
        }
    }
    public static String bigDigitDivide(String var1,String var2){
        //被除数比除数小的情况
        if(var1.length()<var2.length()){
            return "0";
        }else if(var1.length()==var2.length()&&var1.compareTo(var2)<0){
            return "0";
        }
        int diff=var1.length()-var2.length();
        String result="0";
        while(diff>=0){
            int addZero=diff;
            String compare=var2;
            int count=0;
            while(addZero-->0){
                compare+="0";
            }
            while(compareStr(var1,compare)){
                var1=bigDigitSubtract(var1,compare);
                count++;
            }
            if(count!=0){
                StringBuilder curResult=new StringBuilder();
                curResult.append(count);
                for(int i=0;i<diff;i++){
                    curResult.append(0);
                }
                result=bigDigitAdd(result,curResult.toString());
            }
            diff--;
        }
        return result;
    }

求平方根

//求平方根--牛顿迭代法
    public static double mathSqrt(double x){
        if(x<0){
            return -1;
        }
        double preicse = 1e-8;
        double root=x;
        while(Math.abs(root-x/root)>preicse){
            root=(root+x/root)/2;
        }
        return root;
    }

二叉搜索树----插入与树形打印

class Node {
        int data;
        Node left;
        Node right;
        Node p;

        public Node(int data, Node left, Node right, Node p) {
            this.data = data;
            this.left = left;
            this.right = right;
            this.p = p;
        }
    }
    //插入
    public void insert(Node x) {
        if (root == null) {
            root = x;
        } else {
            Node i = root;
            Node j = i;
            while (i != null) {
                j = i;
                if (i.data < x.data) {
                    i = i.right;
                } else {
                    i = i.left;
                }
            }
            x.p = j;
            if (j.data < x.data) {
                j.right = x;
            } else {
                j.left = x;
            }
        }
    }
    //树形打印
    public void printTree(Node root){
        if(root==null){
            return;
        }
        //获得树的高度
        int h = this.getHeight(root,0)+1;
        //构建矩阵,存储树
        String[][] matrix = new String[h][2<<(h-1)];
        for(int i=0;i<matrix.length;i++){
            for(int j=0;j<matrix[i].length;j++){
                matrix[i][j]=" ";
            }
        }
        //确认根位置,上一层位置,当前层起始位置
        //使用队列广度优先遍历树
        //如果树节点为空且在以h-1为高度的满二叉树范围内则插入一个临时节点用来构建矩阵
        int baseP=(2<<(h-1))>>1;
        int prevP=baseP;
        int curP=prevP-(prevP>>1);
        int layer=0;
        LinkedList<Node> queue = new LinkedList<>();
        queue.offer(root);
        matrix[layer++][baseP]=String.valueOf(root.data);
        while(!queue.isEmpty()){
            if(curP>=(baseP<<1)){
                prevP>>=1;
                curP=prevP-(prevP>>1);
                layer++;
            }
            Node node=queue.poll();
            if(node.left!=null&&node.data!=-1){
                queue.offer(node.left);
                matrix[layer][curP]=String.valueOf(node.left.data);
            }else{
                if(layer<h-1) {
                    queue.offer(new Node(-1, null, null, null));
                }
            }
            curP+=prevP;
            if(node.right!=null&&node.data!=-1){
                queue.offer(node.right);
                matrix[layer][curP]=String.valueOf(node.right.data);
            }else{
                if(layer<h-1) {
                    queue.offer(new Node(-1, null, null, null));
                }
            }
            curP+=prevP;
        }
        //打印树
        for(int i=0;i<matrix.length;i++){
            for(int j=0;j<matrix[i].length;j++){
                System.out.print(matrix[i][j]);
            }
            System.out.println();
        }
    }

平衡二叉树插入查找

//节点定义
class Node{
        int data;
        Node left;
        Node right;
        Node p;
        public Node(int data, Node left, Node right, Node p) {
            this.data = data;
            this.left = left;
            this.right = right;
            this.p = p;
        }
    }
//获得树高度,递归为null返回0
public int getHeight(Node node){
        if(node==null){
            return 0;
        }
        int l=1+getHeight(node.left);
        int r=1+getHeight(node.right);
        return Math.max(l,r);
    }
 
//获得树左右子树高度差
    public int getSubtractH(Node node){
        return getHeight(node.left)-getHeight(node.right);
    }
//获得从当前节点开始遍历的最大值
public Node findMax(Node node){
        Node i=node;
        Node j=i;
        while(i!=null){
            j=i;
            i=i.right;
        }
        return j;
    }
//获得从当前节点开始遍历的最小值
public Node findMin(Node node){
        Node i=node;
        Node j=i;
        while(i!=null){
            j=i;
            i=i.left;
        }
        return j;
    }
//四种旋转方式
//左逆旋转,传入节点为第一个不平衡节点
    public void rotateL(Node node){
        Node child = node.right;
        node.right=child.left;
        child.left=node;
        child.p=node.p;
        if(node.p==null){
            root=child;
        }else{
            if(node.p.right==node) {
                node.p.right = child;
            }else{
            //考虑左子树进行左逆旋转
                node.p.left=child;
            }
        }
        node.p=child;

    }
    //左逆右顺,左逆:不平衡节点的子节点与子节点的右节点交换,右顺:不平衡节点与子节点交换
    public void rotateLR(Node node){
        Node child = node.left;
        Node right = child.right;
        //左逆
        child.right=right.left;
        if(right.left!=null){
            right.left.p=child;
        }
        right.left=child;
        right.p=child.p;
        child.p=right;
        node.left=right;
        //右顺
        rotateR(node);
    }
    //右顺左逆
    public void rotateRL(Node node){
        //右顺
        Node child = node.right;
        Node left = child.left;
        child.left=left.right;
        if(left.right!=null){
            left.right.p=child;
        }
        left.right=child;
        left.p=child.p;
        child.p=left;
        node.right=left;
        //左逆
        rotateL(node);
    }
    //右顺旋转
    public void rotateR(Node node){
        Node child = node.left;
        node.left=child.right;
        child.right=node;
        child.p=node.p;
        if(node.p==null){
            root=child;
        }else{
            if(node.p.left==node) {
                node.p.left = child;
            }else{
                node.p.right = child;
            }
        }
        node.p=child;
    }
//重构平衡
public void reBuildTree(Node node){
        //从插入节点开始回溯到第一个左右子树不平衡的根节点
        Node i=node;
        while(i!=null){
            int factor=getSubtractH(i);
            if(factor<=-2){
                //插入节点在右子树的情况,rotateL或则rotateRL
                if(getSubtractH(i.right)>0){
                    rotateRL(i);
                }else{
                    rotateL(i);
                }
                break;
            }else if(factor>=2){
                //插入节点在左子树的情况,rotateR或rotateLR,同时考虑考虑删除时左右节点都存在
                if(getSubtractH(i.left)>=0){
                    rotateR(i);
                }else{
                    rotateLR(i);
                }
                break;
            }
            i=i.p;
        }
    }
//根据插入节点来平衡二叉树,从插入节点往上递归至第一个不平衡的父节点
public void insert(Node node){
        if(root==null){
            root=node;
        }else{
            Node i = root;
            Node j = i;
            while(i!=null){
                j=i;
                if(i.data<node.data){
                    i=i.right;
                }else{
                    i=i.left;
                }
            }
            node.p=j;
            if(node.data<=j.data){
                j.left=node;
            }else{
                j.right=node;
            }
        }
        reBuildTree(node);
    }
//删除时平衡二叉树,1.不存在子节点 2.存在一个子节点 3.存在两个子节点,重新平衡删除后的树
public void delete(Node node) {
        if (node == null) {
            System.out.println("删除节点错误!");
            return;
        }
        Node p = node.p;
        if (node.left == null && node.right == null) {
            if(p==null){
                root=null;
                return ;
            }
            if (p.left == node) {
                p.left = null;
            } else {
                p.right = null;
            }
        } else if (node.right == null) {
            if(p==null){
                root=node.left;
                node.left.p=null;
                return;
            }else {
                if (p.left == node) {
                    p.left = node.left;
                    node.left.p = p;
                } else {
                    p.right = node.left;
                    node.left.p = p;
                }
            }
        } else if (node.left == null) {
            if(p==null){
                root=node.right;
                node.right.p=null;
                return;
            }else {
                if (p.left == node) {
                    p.left = node.right;
                    node.right.p = p;
                } else {
                    p.right = node.right;
                    node.right.p = p;
                }
            }
        } else {
            //同时存在,找到右节点中的最大值来代替删除节点
            Node min = null;
            if(getSubtractH(node)<0){
                min=findMin(node.right);
                if(min.p!=node) {
                    min.p.left = min.right;
                }else{
                    node.right=min.right;
                }
            }else{
                min=findMax(node.left);
                if(min.p!=node) {
                    min.p.right = min.left;
                }else{
                    node.left=min.left;
                }
            }
            min.p=p;
            if(p==null){
                root=min;
                min.left=node.left;
                min.right=node.right;
                if(node.left!=null) {
                    node.left.p = min;
                }
                if(node.right!=null) {
                    node.right.p = min;
                }
                return;
            }else {
                if (p.left == node) {
                    p.left = min;
                    min.left = node.left;
                    min.right = node.right;
                    if(node.left!=null) {
                        node.left.p = min;
                    }
                    if(node.right!=null) {
                        node.right.p = min;
                    }
                } else {
                    p.right = min;
                    min.left = node.left;
                    min.right = node.right;
                    if(node.left!=null) {
                        node.left.p = min;
                    }
                    if(node.right!=null) {
                        node.right.p = min;
                    }

                }
            }
        }
        //不为根的节点判断删除后平衡
        if(getSubtractH(p)>=2||getSubtractH(p)<=-2){
            reBuildTree(p);
        }
    }

23树理解

//自底向上分裂
//2键转换为3键,3键将中键给父节点

红黑树

//节点定义
class Node{
        int data;
        Node p;
        Node left;
        Node right;
        boolean red;

        public Node(int data, Node p, Node left, Node right, boolean red) {
            this.data = data;
            this.p = p;
            this.left = left;
            this.right = right;
            this.red = red;
        }
    }
     /**
     * @description 通过旋转和变色重新平衡红黑树
     * @param node
     */
    public void reBalance(Node node){
        Node p = node.p;
        //如果为根节点则将根节点置黑
        if(p==null){
            node.red=false;
            return;
        }
        //如果父节点为黑不用重新平衡
        //如果父节点为红,因为根节点始终为黑所以父节点为红必定存在祖父节点
        if(p.red){
            Node pp = p.p;
            //如果父节点为祖父节点的左节点
            if(p==pp.left){
                //如果父节点的兄弟节点不为红则进行rotateR和rotateLR
                if(pp.right==null||!pp.right.red){
                    //如果插入节点为左节点,对父节点进行右顺旋转
                    if(p.left==node){
                        rotateR(p);
                    }else{
                        //父节点左逆右顺旋转
                        rotateLR(p);
                    }
                }else{
                    //如果父节点的兄弟节点为红,黑红红->红黑红,重新平衡祖父节点
                    p.red=false;
                    pp.right.red=false;
                    pp.red=true;
                    reBalance(pp);
                }
            }
            //如果父节点为祖父节点的右节点
            else{
                //如果父节点的兄弟节点不为红则进行rotateL和rotateRL
                if(pp.left==null||!pp.left.red){
                    //如果插入节点是右节点
                    if(p.right==node){
                        rotateL(p);
                    }else{
                        rotateRL(p);
                    }
                }else{
                    //如果父节点的兄弟节点为红,黑红红->红黑红,重新平衡祖父节点
                    p.red=false;
                    pp.left.red=false;
                    pp.red=true;
                    reBalance(pp);
                }
            }
        }
    }
    //插入节点及重新平衡
    public void insert(Node node){
        //根节点为空
        if(root==null){
            root=node;
            root.red=false;
            return;
        }
        Node i=root;
        Node j=i;
        while(i!=null){
            j=i;
            if(node.data>i.data){
                i=i.right;
            }else{
                i=i.left;
            }
        }
        node.p=j;
        if(node.data>j.data){
            j.right=node;
        }else{
            j.left=node;
        }
        reBalance(node);
    }
    //4中旋转方式
    public void rotateR(Node node){
        Node p = node.p;
        //变色
        p.red=true;
        node.red=false;
        //右旋
        p.left=node.right;
        if(node.right!=null){
            node.right.p=p;
        }
        node.right=p;
        node.p=p.p;
        //如果父节点为根节点
        if(p.p==null){
            root=node;
        }else{
            if(p.p.left==p){
                p.p.left=node;
            }else{
                p.p.right=node;
            }
        }
        p.p=node;

    }
    public void rotateL(Node node){
        Node p = node.p;
        //变色
        node.red=false;
        p.red=true;
        //左旋
        p.right=node.left;
        if(node.left!=null){
            node.left.p=p;
        }
        node.left=p;
        node.p=p.p;
        if(p.p==null){
            root=node;
        }else{
            if(p.p.right==p){
                p.p.right=node;
            }else{
                p.p.left=node;
            }
        }
        p.p=node;
    }
    public void rotateLR(Node node){
        Node child = node.right;
        //左逆旋转
        node.right=child.left;
        if(child.left!=null){
            child.left.p=node;
        }
        child.left=node;
        child.p=node.p;
        node.p.left=child;
        node.p=child;
        rotateR(child);
    }
    public void rotateRL(Node node){
        Node child = node.left;
        //右顺旋转
        node.left=child.right;
        if(child.right!=null){
            child.right.p=node;
        }
        child.right=node;
        child.p=node.p;
        node.p.right=child;
        node.p=child;
        //左逆
        rotateL(child);
    }
    //删除
    public void delete(Node node){
        Node i = root;
        while(i!=null){
            if(i==node){
                deleteReBalance(i);
                return;
            }else if(i.data>node.data){
                i=i.left;
            }else{
                i=i.right;
            }
        }
    }
    //删除后平衡
    public void deleteReBalance(Node node){
        if(node.left!=null&&node.right!=null){
            //左右节点都存在,取前驱或后继转换成只存在一个节点|不存在子节点
            Node substitute=maxNode(node.left);
            //交换删除节点和代替节点,将删除当前节点改为删除代替节点
            node.data=substitute.data;
            deleteReBalance(substitute);
        }else if(node.left!=null||node.right!=null){
            //根据红黑树性质,只有一个节点时只存在黑->红的情况,直接用子节点代替删除节点
            node.data=node.left==null?node.right.data:node.left.data;
            if(node.left==null){
                node.right.p=null;
                node.right=null;
            }else{
                node.left.p=null;
                node.left=null;
            }
        }else{
            if(node.p==null){
                root=null;
                return ;
            }
            //如果没有子节点,且删除节点为红色,直接删除
            if(node.red){
                if(node.p.left==node){
                    node.p.left=null;
                    node.p=null;
                }else{
                    node.p.right=null;
                    node.p=null;
                }
            }else{
                Node in = node;
                while(in.p!=null) {
                    //删除节点为黑
                    Node p = in.p;
                    //如果删除节点为父节点的左子树
                    if (in == p.left) {
                        Node s = p.right;
                        //如果兄弟节点是黑色或空
                        if (s == null || !s.red) {
                            //如果兄弟节点的远子侄存在
                            if (s.right != null && s.right.red) {
                                //删除节点
                                p.left = null;
                                in.p = null;
                                //变色,交换父和兄节点颜色,子侄置黑
                                s.right.red = false;
                                boolean flag = p.red;
                                /*p.red = s.red;
                                s.red = flag;*/
                                //左旋转
                                rotateL(s);
                                s.red=flag;
                                p.red=false;
                                break;
                            }
                            //如果近子侄存在
                            else if (s.left != null && s.left.red) {
                                //变色,交换兄与子侄颜色
                                s.left.red = s.red;
                                s.red = true;
                                //旋转变为远子侄情况
                                Node i = s.left;
                                s.left = i.right;
                                if (i.right != null) {
                                    i.right.p = s;
                                }
                                i.right = s;
                                i.p = s.p;
                                p.right = i;
                                s.p = i;
                            }
                            //兄弟节点无孩子或都为黑且父为红
                            else if (p.red) {
                                //删除节点
                                p.left = null;
                                node.p = null;
                                //父变黑,兄变红
                                p.red = false;
                                s.red = true;
                                break;
                            }
                            //兄弟节点无孩子或都为黑且父为黑
                            else {
                                //如果为删除节点则删除
                                if(in==node){
                                    p.left = null;
                                    node.p = null;
                                }
                                s.red=true;
                                in=p;
                            }
                        }
                        //兄弟节点是红色
                        else {
                            //删除
                            p.left = null;
                            in.p = null;
                            //兄弟节点变色左旋
                            rotateL(s);
                            break;
                        }
                    }
                    //如果删除节点为父节点的右子树
                    else {
                        Node s = p.left;
                        //如果兄弟节点是黑色或空
                        if (s == null || !s.red){
                            //如果远子侄为红色
                            if(s.left!=null&&s.left.red){
                                //删除节点
                                p.right = null;
                                in.p = null;
                                //变色,交换父和兄节点颜色,子侄置黑
                                s.left.red = false;
                                boolean flag = p.red;
                                /*p.red = s.red;
                                s.red = flag;*/
                                //左旋转
                                rotateR(s);
                                s.red=flag;
                                p.red=false;
                                break;
                            }
                            //如果近子侄为红色
                            else if(s.right!=null&&s.right.red){
                                //变色,交换兄与子侄颜色
                                s.right.red = s.red;
                                s.red = true;
                                //旋转变为远子侄情况
                                Node i = s.right;
                                s.right = i.left;
                                if (i.left != null) {
                                    i.left.p = s;
                                }
                                i.left = s;
                                i.p = s.p;
                                p.left = i;
                                s.p = i;
                            }
                            //如果父节点为红
                            else if(p.red){
                                //删除节点
                                p.left = null;
                                node.p = null;
                                //父变黑,兄变红
                                p.red = false;
                                s.red = true;
                                break;
                            }
                            //如果父为黑
                            else{
                                //如果为删除节点则删除
                                if(in==node){
                                    p.left = null;
                                    node.p = null;
                                }
                                s.red=true;
                                in=p;
                            }
                        }
                    }
                }
            }
        }
    }

graham扫描法求凸包

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值