• 几个常见的算法


     递归算法:自己调用自己

              1.计算乘法1*2..... (n-1)*n的积

             public static int getReult(int num){

                       if(num==0){

                                return 0;

                       }

                       if(num==1){

                                return 1;

                       }

                       return num*getReult(num-1);

             }

             2.100以内的阶乘

              public static BigInteger sum(int i) { 

                     if (i == 1) {   return BigInteger.ONE;  } 

                     return BigInteger.valueOf(i).multiply(sum(i-1)); 

               } 

            

             /**

              * 计算从1+...num 的和

              * 10000以内

              * @param num

              * @return

              */

             public static int getSumReult(int num){

                       if(num==0){

                                return 0;

                       }

                       if(num==1){

                                return 1;

                       }

                       return num+getSumReult(num-1);

             }

    /***

        * 二分法查找:二分查找 二分查找也称折半查找(Binary

        * Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,

        * 而且表中元素按关键字有序排列。

        */

       public static int findTag(int a[], int tag) {

          int start=0;

           int end=a.length;

           for (int i = 0; i < a.length; i++) {

             int mid=(start+end)/2;

            if(tag==a[mid]){

               return mid;

            }

            if(tag>a[mid]){

               start=mid+1;

            }

            if(tag<a[mid]){

               end=mid-1;

            }

          }

          return -1;//没有找到

       }

    /**

        * 选择排序

        * @param numbers

        * @return

        */

       public static int[] selectSortNew(int[] numbers){

          int  tempData;

          for(int i = 0; i < numbers.length; i++){

             int k = i;////假设k的下标的值最小

             for (int j = numbers.length-1; j >i; j--){

                if (numbers[k] > numbers[j]){

                   k = j;

                }

             }

              tempData = numbers[i];

              numbers[i]=numbers[k];

              numbers[k]=tempData;

          }

          return numbers;

       }

      

       public static void main(String[] args) {

          int a[] = { 21,35,56,57,90,78,101};

          int b[] = selectSortNew(a);

          System.out.println(Arrays.toString(b));

         

       }

     

         /**

         * 快速排序

         * @param numbers

         * @param start

         * @param end

         * @return

         */

       public static int[]  quickSortNew(int[] numbers, int start, int end) {  

           if (start < end) {  

               int base = numbers[start]; // 选定的基准值(第一个数值作为基准值)  

               int temp; // 记录临时中间值  

               int i = start, j = end;  

               do {  

                   while ((numbers[i] < base) && (i < end))  

                       i++;  

                   while ((numbers[j] > base) && (j > start))  

                       j--;  

                   if (i <= j) {  

                       temp = numbers[i];  

                       numbers[i] = numbers[j];  

                       numbers[j] = temp;  

                       i++;  

                       j--;  

                   }  

               } while (i <= j);  

              

               if (start < j)  

                 quickSortNew(numbers, start, j);  

              

               if (end > i)  

                 quickSortNew(numbers, i, end); 

           }  

           return numbers;

       }

      

       public static void main(String[] args) {

          int a[] = { 21,35,56,57,90,78,101};

          int b[] = quickSortNew(a,0,6);

          System.out.println(Arrays.toString(b));

         

       }

     

           // 冒泡排序算法 效率低

          public static int[] BubbleSortInt(int[] array) {

     

            int temp;

            for (int i = 0; i < array.length; i++) {

               for (int j = array.length - 1; j > i; j--) {

                  if (array[j - 1] > array[j]) {

                     // 如果前面一个数大于后面一个数则交换

                     temp = array[j - 1];

                     array[j - 1] = array[j];

                     array[j] = temp;

                  }

               }

     

            }

     

            return array;

          }

         

          public static void main(String[] args) {

            int a[] = { 21,35,56,57,90,78,101};

            int b[] = BubbleSortInt(a);

            System.out.println(Arrays.toString(b));

          }

    }

    /*

           * 直接插入排序 1、首先比较数组的前两个数据,并排序;

           * 2、比较第三个元素与前两个排好序的数据,并将第三个元素放入适当的位置;

           * 3、比较第四个元素与前三个排好序的数据,并将第四个元素放入适当的位置;

           * 4、直至把最后一个元素放入适当的位置。

           * 直接插入排序是稳定的。直接插入排序的平均时间复杂度为O(n2)。

           */

          public static int[]  sortChaRu(int[] arr) {

               int tmp;

              //无须序列

               for(int i = 1; i < arr.length; i++) {

                   // 待插入数据

                   tmp = arr[i];

                   int j;

                  

                   //有序序列

                   for(j = i - 1; j >= 0; j--) {

                       // 判断是否大于tmp,大于则后移一位

                       if(arr[j] > tmp) {

                           arr[j+1] = arr[j];

                       }else{

                           break;

                       }

                   }

                   arr[j+1] = tmp;

               }

               return arr;

           }

         

          public static void main(String[] args) {

            int a[] = { 21,35,56,57,90,78,101};

            int b[] = sortChaRu(a);

            System.out.println(Arrays.toString(b));

          }

    String数组中取出相同的字符串

              把数组A的数据作为map的key和value, 然后用B的数据取值,不为NULL,说明相同Map接口 Map提供了一种映射关系,其中的元素是以键值对(key-value)的形式存储的,能够实现根据key快速查找value;Map中的键值对以Entry类型的对象实例形式存在;建(key值)不可重复,value值可以重复,一个value值可以和很多key值形成对应关系,每个建最多只能映射到一个值。

    Map支持泛型,形式如:Map<K,V> Map中使用put(K key,V value)方法添加, HashMap类 HashMap是Map的一个重要实现类,也是最常用的,基于哈希表实现 HashMap中的Entry对象是无序排列的

    Key值和value值都可以为null,但是一个HashMap只能有一个key值为null的映射(key值不可重复)

             public static List<String> getSameElementByMap(String[] strArr1, String[] strArr2) {

                       // HashMap key值 不可重复 Key值和value值都可以为null

                       HashMap<String, Object> map = new HashMap<String, Object>();

                       // 数组A中的元素放入Map中

                       for (String string1 : strArr1) {

                                map.put(string1, string1);

                       }

                       List<String> list = new ArrayList<String>();

                       // 用数组B元素做为Key来取值,如为NULL则说明相同

                       for (String string2 : strArr2) {

                                Object j = map.get(string2);

                                if (j != null) {

                                         list.add(string2);

                                         // System.out.println("数组AB中相同的元素: "+j.toString());

                                }    }

                       return list;

             }

    测试例子:

    public static void main(String[] args) {             

    String[] strArr1 = { "21002023","21002030","21002225","21002389","21002393","21002396"};

    String[] strArr2 = { "21002023","21002030","21002225","21002389","21002393","21002396",

                                         "21002012","21002222","21002407"};

                       System.out.println(getSameElementByMap(strArr1, strArr2).toString());

                       int res1=getReult(12);

                       System.out.println(res1);

                      

                       BigInteger res=sum(12);

                       System.out.println(res);

                       int sun=getSumReult(10000);

                       System.out.println(sun);

             }

    }

     两个大于1000的数的乘积

     public class NumDividEqual {

                 public char[] A;

                 public char[] B;

                 int n;

                 /**

                  * 将数组均分为两份,分别存入数组A和数组B中;

                  * @param input

                  */

                 public NumDividEqual(char[] input){

                     n = input.length/2;

                     A = new char[n];

                     B = new char[n];

                     for(int i = 0; i<n;i++){

                         A[i] = input[i];

                     }

                     for(int i = 0; i<n;i++){

                         B[i] = input[i + n];

                     }     

                 }

              

                 public static void main(String[] args) {

                     // TODO Auto-generated method stub

                 }

    }

    package com.hyhl.test;

    import java.util.Arrays;

    public class BigIntMult {

            

              /**

         * 将字符数组倒序排列

         * @param input

         * @return

         */

        public char[] reverse(char[] input) {

            char[] output = new char[input.length];

            for (int i = 0; i < input.length; i++) {

                output[i] = input[input.length - 1 - i];

            }

            return output;

        }

       

        /**

         * 将大整数平均分成两部分

         * @param input

         * @return

         */

        public NumDividEqual partition(char[] input) {

            return new NumDividEqual(input);

        }

        /**

         * 求两数组中较大数组的长度,如果其长度为奇数则+1变偶

         * @param num1

         * @param num2

         * @return

         */

        public int calLength(char[] num1, char[] num2) {

            int len = num1.length > num2.length ? num1.length : num2.length;

            if (len == 1)

                return 1;

            len += len & 1;

            return len;

        }

        /**

         * 除去数字前面多余的0

         * @param input

         * @return

         */

        public static char[] trimPrefix(char[] input) {

            char[] ret = null;

            for (int i = 0; i < input.length; i++) {

                if (ret == null && input[i] == '0')

                    continue;

                else {

                    if (ret == null) {

                        ret = new char[input.length - i];//出去数字前面多余的0

                    }

                    ret[i - (input.length - ret.length)] = input[i];

                }

            }

            if (ret == null)

                return new char[] { '0' };

            return ret;

        }

       

        /**

         * 数组如果长度不足n,则在数组前面补0,使长度为n。

         * @param input 输入数组要求数字的最高位存放在数组下标最小位置

         * @param n

         * @return

         */

        public static char[] format(char[] input, int n) {//;

            if (input.length >= n) {

                return input;

            }

            char[] ret = new char[n];

            for (int i = 0; i < n - input.length; i++) {

                ret[i] = '0';

            }

            for (int i = 0; i < input.length; i++) {

                ret[n - input.length + i] = input[i];

            }

            return ret;

        }

        /**

         * 大整数尾部补0。相当于移位,扩大倍数

         * @param input

         * @param n

         * @return

         */

        public char[] addTail(char[] input, int n) {//

            char[] ret = new char[input.length + n];

            for (int i = 0; i < input.length; i++) {

                ret[i] = input[i];

            }

            for (int i = input.length; i < ret.length; i++) {

                ret[i] = '0';

            }

            return ret;

        }

       

        /**

         * 大整数加法

         * @param num1

         * @param num2

         * @return

         */

        public char[] add(char[] num1, char[] num2) {

            int len = num2.length > num1.length ? num2.length : num1.length;

            int carry = 0;//进位标识

            num1 = format(num1, len);

            num2 = format(num2, len);

            char[] ret = new char[len + 1];

            for (int i = len - 1; i >= 0; i--) {

                int tmp = num1[i] + num2[i] - 96;

                tmp += carry;

                if (tmp >= 10) {

                    carry = 1;

                    tmp = tmp - 10;

                } else {

                    carry = 0;

                }

                ret[len - i - 1] = (char) (tmp + 48);

            }

            ret[len] = (char) (carry + 48);//最后一次,最高位的进位

            return trimPrefix(reverse(ret));

        }

        /**

         * 大整数减法:

         * @param num1 被减数,大整数乘法中只有一个减法(A+B)(C+D)-(AC+BD)=AC+BC>0,因此參數num1>num2且都为正

         * @param num2 减数

         * @return

         */

        public static char[] sub(char[] num1, char[] num2) {

            int lenMax = num1.length > num2.length ? num1.length : num2.length;

            char[] newNum1 = Arrays.copyOf(format(num1, lenMax), lenMax);//字符串前面补0,使两串长度相同

            char[] newNum2 = Arrays.copyOf(format(num2, lenMax), lenMax);

           

            for(int i=0;i<lenMax;i++){//when num1-num2<0 return

                if((newNum1[i]=='0' && newNum1[i]=='0') || newNum1[i] == newNum2[i]){//newNum1 is bigger; 

                    continue;

                }

                else if(newNum1[i] < newNum2[i]){//不滿足參數num1>num2;

                        System.out.println("The Parameter in sub(A,B).A MUST Bigger Than B!");

                        System.exit(0);

                     }

                else break;

            }

            for(int i=lenMax-1;i>=0;i--){

                if(newNum1[i] < newNum2[i]){//result < 0

                 newNum1[i] = (char) (newNum1[i] + '0' + 10 - newNum2[i]);

                 newNum1[i-1] = (char) (newNum1[i-1] - 1);

                }

                else{

                    newNum1[i] = (char) (newNum1[i] + '0' - newNum2[i]);

                }

            }

            return trimPrefix(newNum1);

        }     

        /**

         * 大整数乘法

         * @param num1

         * @param num2

         * @return

         */

        public char[] mult(char[] num1, char[] num2) {

            char[] A, B, C, D, AC, BD, AjB, CjD, ACjBD, AjBcCjD,  SUM;

            int N = calLength(num1, num2);//求两数组中较大数组的长度,如果长度为奇数则+1变偶,方便二分成两部分

            num1 = format(num1, N);//数组高位存整数的高位数;数字前面补0,使长度为n;

            num2 = format(num2, N);

            if (num1.length > 1) {

                NumDividEqual nu1 = partition(num1);//将大整数平均分成两部分

                NumDividEqual nu2 = partition(num2);

                A = nu1.A;

                B = nu1.B;

                C = nu2.A;

                D = nu2.B;

                AC = mult(A, C);//分治求大整数乘法

                BD = mult(B, D);

                AjB = add(A,B);

                CjD = add(C,D);

                ACjBD = add(AC,BD);

                AjBcCjD = mult(AjB, CjD);

               

                char[] tmp1 = addTail(sub(AjBcCjD, ACjBD), N / 2);//尾部补0,相当于移位

                char[] tmp2 = add(addTail(AC, N), BD);

                SUM = add(tmp1, tmp2);

                char[] test = trimPrefix(SUM);//除去结果前面多余的0

                return test;

            } else {

                Integer ret = (num1[0] - 48) * (num2[0] - 48);

                return ret.toString().toCharArray();

            }

        }

       

        public static void main(String[] args) {

            String st1 = "16874631564134797979843343322342245222344533334432223345224432212";

            String st2 = "1646816547674468877974513161584444444221333498800000998898383818191292098887773999919";

            char[] a = st1.toCharArray();

            char[] b = st2.toCharArray();

            BigIntMult bg = new BigIntMult();

           

            //大整数乘法

            char[] ret = bg.mult(a, b);

           

            System.out.println(ret);

        }

    }

    算法:

    插入排序的时间复杂度为:O(N^2)

    希尔排序的时间复杂度为:平均为:O(N^3/2)    最坏: O(N^2)

    归并排序时间复杂度为: O(NlogN)   空间复杂度为:  O(N)

    1.堆排序

    public int[] heapSort(int[] array) {

                       // 初始建堆,array[0]为第一趟值最大的元素

                       array = buildMaxHeap(array);

                       for (int i = array.length - 1; i > 1; i--) {

                                // 将堆顶元素和堆低元素交换,即得到当前最大元素正确的排序位置

                                int temp = array[0];

                                array[0] = array[i];

                                array[i] = temp;

                                // 整理,将剩余的元素整理成堆

                                adjustDownToUp(array, 0, i);

                       }

                       return array;

             }

             // 构建大根堆:将array看成完全二叉树的顺序存储结构

             private int[] buildMaxHeap(int[] array) {

                       // 从最后一个节点array.length-1的父节点(array.length-1-1)/2开始,直到根节点0,反复调整堆

                       for (int i = (array.length - 2) / 2; i >= 0; i--) {

                                adjustDownToUp(array, i, array.length);

                       }

                       return array;

             }

             // 将元素array[k]自下往上逐步调整树形结构

             private void adjustDownToUp(int[] array, int k, int length) {

                       int temp = array[k];

                       for (int i = 2 * k + 1; i < length - 1; i = 2 * i + 1) { // i为初始化为节点k的左孩子,沿节点较大的子节点向下调整

                                if (i < length && array[i] < array[i + 1]) { // 取节点较大的子节点的下标

                                         i++; // 如果节点的右孩子>左孩子,则取右孩子节点的下标

                                }

                                if (temp >= array[i]) { // 根节点 >=左右子女中关键字较大者,调整结束

                                         break;

                                } else { // 根节点 <左右子女中关键字较大者

                                         array[k] = array[i]; // 将左右子结点中较大值array[i]调整到双亲节点上

                                         k = i; // 【关键】修改k值,以便继续向下调整

                                }

                       }

                       array[k] = temp; // 被调整的结点的值放人最终位置

             }

           

    6.希尔排序

     希尔排序(缩小增量法)属于插入类排序,由Shell提出,希尔排序对直接插入排序进行了简单的改进:它通过加大插入排序中元素之间的间隔,并在这些有间隔的元素中进行插入排序, 从而使数据项大跨度地移动,当这些数据项排过一趟序之后,希尔排序算法减小数据项的间隔再进行排序,依次进行下去, 进行这些排序时的数据项之间的间隔被称为增量,习惯上用字母h来表示这个增量。

    常用的h序列由Knuth提出,该序列从1开始,通过如下公式产生: h = 3 * h +1反过来程序需要反向计算h序列,应该使用h=(h-1)/3

              */

             public static int[] shellSort(int[] data) {

                       // 计算出最大的h值

                       int h = 1;

                       while (h <= data.length / 3) {

                                h = h * 3 + 1;

                       }

                       while (h > 0) {

                                for (int i = h; i < data.length; i += h) {

                                         if (data[i] < data[i - h]) {

                                                   int tmp = data[i];

                                                   int j = i - h;

                                                   while (j >= 0 && data[j] > tmp) {

                                                            data[j + h] = data[j];

                                                            j -= h;

                                                   }

                                                   data[j + h] = tmp;

                                         }

                                }

                                // 计算出下一个h值

                                h = (h - 1) / 3;

                       }

                       return data;

             }

    1. 7.   /**    

              * 归并排序 分而治之(divide - conquer);

              *  每个递归过程涉及三个步骤

              *  第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列,每个子序列包括 n/2 个元素.

              *  第二, 治理: 对每个子序列分别调用归并排序MergeSort, 进行递归操作

              *  第三, 合并: 合并两个排好序的子序列,生成排序结果.

              * (1)稳定性 归并排序是一种稳定的排序。

              * (2)存储结构要求 可用顺序存储结构。也易于在链表上实现。

              * (3)时间复杂度对长度为n的文件,需进行趟二路归并,每趟归并的时间为O(n),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(nlgn)。

              * (4)空间复杂度 需要一个辅助向量来暂存两有序子文件归并的结果,故其辅助空间复杂度为O(n),显然它不是就地排序

              * 注意:若用单链表做存储结构,很容易给出就地的归并排序

              */

             public static int[] mergeSort(int[] a, int low, int high) {

                       int mid = (low + high) / 2;

                       if (low < high) {

                                mergeSort(a, low, mid);

                                mergeSort(a, mid + 1, high);

                                // 左右归并

                                merge(a, low, mid, high);

                       }

                       return a;

             }

             public static void merge(int[] a, int low, int mid, int high) {

                       int[] temp = new int[high - low + 1];

                       int i = low;

                       int j = mid + 1;

                       int k = 0;

                       // 把较小的数先移到新数组中

                       while (i <= mid && j <= high) {

                                if (a[i] < a[j]) {

                                         temp[k++] = a[i++];

                                } else {

                                         temp[k++] = a[j++];

                                }

                       }

                       // 把左边剩余的数移入数组

                       while (i <= mid) {

                                temp[k++] = a[i++];

                       }

                       // 把右边边剩余的数移入数组

                       while (j <= high) {

                                temp[k++] = a[j++];

                       }

                       // 把新数组中的数覆盖nums数组

                       for (int x = 0; x < temp.length; x++) {

                                a[x + low] = temp[x];

                       }

             }

    ------------------------5种查找------------------------------------------------------------------

    线性查找分为:顺序查找、折半查找。

    查找有两种形态:

    分为:破坏性查找,比如有一群mm,我猜她们的年龄,第一位猜到了是23+,此时这位mm已经从我脑海里面的mmlist中remove掉了。哥不找23+的,所以此种查找破坏了原来的结构。非破坏性查找, 这种就反之了,不破坏结构。

    顺序查找:这种非常简单,就是过一下数组,一个一个的比,找到为止。

     1   // 顺序查找

             public static int SequenceSearch(int[] array, int key) {

                       for (int i = 0; i < array.length; i++) {

                                // 查找成功,返回序列号

                                if (key == array[i])

                                         return i;

                       }

                       // 未能查找,返回-1

                       return -1;

             }

    2. 折半查找 长度必须是奇数

              第一: 数组必须有序,不是有序就必须让其有序,大家也知道最快的排序也是NLogN

              第二: 这种查找只限于线性的顺序存储结构。

             public static int BinarySearchNew(int[] array, int tag) {

                       int frist = 0;

                       int end = array.length;

                       for (int i = 0; i < array.length; i++) {

                                int middle = (frist + end) / 2;

                                if (tag == array[middle]) {

                                         // 正好相等 则返回查询结果

                                         return middle;

                                }

                                if (tag > array[middle]) {

                                         // 大于 middle

                                         frist = middle + 1;

                                }

                                if (tag < array[middle]) {

                                         // 下于 middle

                                         end = middle - 1;

                                }

                      }

                       return -1;

             }

    线性查找时间复杂度:O(n);

    折半无序(用快排活堆排)的时间复杂度:O(NlogN)+O(logN);

    折半有序的时间复杂度:O(logN);

    3其实常用的做哈希的手法有“五种”

    第一种:”直接定址法“:很容易理解,key=Value+C; 这个“C"是常量。Value+C其实就是一个简单的哈希函数。

    第二种:“除法取余法”: 很容易理解, key=value%C;解释同上。

    第三种:“数字分析法”:比如有一组value1=112233,value2=112633,value3=119033, 针对这样的数我们分析数中间两个数比较波动,其他数不变。那么我们取key的值就可以是key1=22,key2=26,key3=90。

    第四种:“平方取中法”。

    第五种:“折叠法”:比如value=135790,要求key是2位数的散列值。那么我们将value变为13+57+90=160, 然后去掉高位“1”,此时key=60,哈哈,这就是他们的哈希关系,这样做的目的就是key与每一位value都相关,来做到“散列地址”尽可能分散的目地。

    解决冲突常用的手法也就2种:

    第一种:开放地址法。

       所谓”开放地址“,其实就是数组中未使用的地址。也就是说,在发生冲突的地方,后到的那个元素(可采用两种方式:①线性探测,②函数探测)向数组后寻找"开放地址“然后把自己插进入。

    第二种:链接法。原理就是在每个元素上放一个”指针域“,在发生冲突的地方,后到的那个元素将自己的数据域抛给冲突中的元素,此时冲突的地方就形成了一个链表。

    设计函数采用:除法取余法。

     冲突方面采用:开放地址线性探测法。

              

    5二叉排序树查找

    1. 概念:

    <1> 其实很简单,若根节点有左子树,则左子树的所有节点都比根节点小。若根节点有右子树,则右子树的所有节点都比根节点大。

        <2> 如图就是一个”二叉排序树“,然后对照概念一比较比较

    /**

     * 二叉排序树

     * 采用广度优先法则来遍历排序二叉树得到的不是有序序列,

     * 采用中序遍历来遍历排序二叉树才可以得到有序序列。

     *

     */

    public class SortedBinTree <T extends Comparable>{

                 static class Node {

                     Object data;

                     Node parent;

                     Node left;

                     Node right;

                     public Node(Object data, Node parent, Node left, Node right) {

                         this.data = data;

                         this.parent = parent;

                         this.left = left;

                         this.right = right;

                     }

                     public String toString() {

                         return "[data=" + data + "]";

                     }

                     public boolean equals(Object obj) {

                         if (this == obj) {

                             return true;

                         }

                         if (obj.getClass() == Node.class) {

                             Node target = (Node) obj;

                             return data.equals(target.data) && left == target.left && right == target.right && parent == target.parent;

                         }

                         return false;

                     }

                 }

                 private Node root;

                 // 两个构造器用于创建排序二叉树

                 public SortedBinTree() {

                     root = null;

                 }

                 public SortedBinTree(T o) {

                     root = new Node(o, null, null, null);

                 }

                 // 添加节点

                 public void add(T ele) {

                     // 如果根节点为null

                     if (root == null) {

                         root = new Node(ele, null, null, null);

                     } else {

                         Node current = root;

                         Node parent = null;

                         int cmp = 0;

                         // 搜索合适的叶子节点,以该叶子节点为父节点添加新节点

                         do {

                             parent = current;

                             cmp = ele.compareTo(current.data);

                             // 如果新节点的值大于当前节点的值

                             if (cmp > 0) {

                                 // 以右子节点作为当前节点

                                 current = current.right;

                             } else {

                                 // 如果新节点的值小于当前节点的值

                                 // 以左节点作为当前节点

                                 current = current.left;

                             }

                         }

                         while (current != null);

                         // 创建新节点

                         Node newNode = new Node(ele, parent, null, null);

                         // 如果新节点的值大于父节点的值

                         if (cmp > 0) {

                             // 新节点作为父节点的右子节点

                             parent.right = newNode;

                         } else {

                             // 如果新节点的值小于父节点的值

                             // 新节点作为父节点的左子节点

                             parent.left = newNode;

                         }

                     }

                 }

                 // 删除节点

                 public void remove(T ele) {

                     // 获取要删除的节点

                     Node target = getNode(ele);

                     if (target == null) {

                         return;

                     }

                     // 左、右子树为空

                     if (target.left == null && target.right == null) {

                         // 被删除节点是根节点

                         if (target == root) {

                             root = null;

                         } else {

                             // 被删除节点是父节点的左子节点

                             if (target == target.parent.left) {

                                 // 将target的父节点的left设为null

                                 target.parent.left = null;

                             } else {

                                 // 将target的父节点的right设为null

                                 target.parent.right = null;

                             }

                             target.parent = null;

                         }

                     } else if (target.left == null && target.right != null) {

                         // 左子树为空,右子树不为空

                         // 被删除节点是根节点

                         if (target == root) {

                             root = target.right;

                         } else {

                             // 被删除节点是父节点的左子节点

                             if (target == target.parent.left) {

                                 // 让target的父节点的left指向target的右子树

                                 target.parent.left = target.right;

                             } else {

                                 // 让target的父节点的right指向target的右子树

                                 target.parent.right = target.right;

                             }

                             // 让target的右子树的parent指向target的parent

                             target.right.parent = target.parent;

                         }

                     } else if (target.left != null && target.right == null) {

                         // 左子树不为空,右子树为空

                         // 被删除节点是根节点

                         if (target == root) {

                             root = target.left;

                         } else {

                             // 被删除节点是父节点的左子节点

                             if (target == target.parent.left) {

                                 // 让target的父节点的left指向target的左子树

                                 target.parent.left = target.left;

                             } else {

                                 // 让target的父节点的right指向target的左子树

                                 target.parent.right = target.left;

                             }

                             // 让target的左子树的parent指向target的parent

                             target.left.parent = target.parent;

                         }

                     } else {

                         // 左、右子树都不为空

                         // leftMaxNode用于保存target节点的左子树中值最大的节点

                         Node leftMaxNode = target.left;

                         // 搜索target节点的左子树中值最大的节点

                         while (leftMaxNode.right != null) {

                             leftMaxNode = leftMaxNode.right;

                         }

                         // 从原来的子树中删除leftMaxNode节点

                         leftMaxNode.parent.right = null;

                         // 让leftMaxNode的parent指向target的parent

                         leftMaxNode.parent = target.parent;

                         // 被删除节点是父节点的左子节点

                         if (target == target.parent.left) {

                             // 让target的父节点的left指向leftMaxNode

                             target.parent.left = leftMaxNode;

                         } else {

                             // 让target的父节点的right指向leftMaxNode

                             target.parent.right = leftMaxNode;

                         }

                         leftMaxNode.left = target.left;

                         leftMaxNode.right = target.right;

                         target.parent = target.left = target.right = null;

                     }

                 }

                 // 根据给定的值搜索节点

                 public Node getNode(T ele) {

                     // 从根节点开始搜索

                     Node p = root;

                     while (p != null) {

                         int cmp = ele.compareTo(p.data);

                         // 如果搜索的值小于当前p节点的值

                         if (cmp < 0) {

                             // 向左子树搜索

                             p = p.left;

                         } else if (cmp > 0) {

                             // 如果搜索的值大于当前p节点的值

                             // 向右子树搜索

                             p = p.right;

                         } else {

                             return p;

                         }

                     }

                     return null;

                 }

                 // 广度优先遍历

                 public List<Node> breadthFirst() {

                     Queue<Node> queue = new ArrayDeque<Node>();

                     List<Node> list = new ArrayList<Node>();

                     if (root != null) {

                         // 将根元素入“队列”

                         queue.offer(root);

                     }

                     while (!queue.isEmpty()) {

                         // 将该队列的“队尾”的元素添加到List中

                         list.add(queue.peek());

                         Node p = queue.poll();

                         // 如果左子节点不为null,将它加入“队列”

                         if (p.left != null) {

                             queue.offer(p.left);

                         }

                         // 如果右子节点不为null,将它加入“队列”

                         if (p.right != null) {

                             queue.offer(p.right);

                         }

                     }

                     return list;

                 }

               

                 //二叉排序的查询

                 public static void main(String[] args) {

                     SortedBinTree<Integer> tree = new SortedBinTree<Integer>();

                     // 添加节点

                     tree.add(5);

                     tree.add(20);

                     tree.add(10);

                     tree.add(3);

                     tree.add(8);

                     tree.add(15);

                     tree.add(30);

                     System.out.println(tree.breadthFirst());

                    

                     // 删除节点

                     tree.remove(20);

                    

                     System.out.println(tree.breadthFirst());

                 }

             }

    值的注意的是:二叉排序树同样采用“空间换时间”的做法。

    突然发现,二叉排序树的中序遍历同样可以排序数组,呵呵,不错!

    PS:  插入操作:O(LogN)。 删除操作:O(LogN)。 查找操作:O(LogN)。

  • 相关阅读:
    使用IDENTITY列属性和Sequence对象
    使用OFFSET-FETCH进行数据过滤
    SQL 插入语句汇总
    建立&修改视图
    Centos 7.x 搭建 Zabbix3.4
    RDS 导出Mysqlbinlog_二进制日志
    Yac
    云服务器漏洞更新
    Centos 内存释放
    Centos 安装 Htop
  • 原文地址:https://www.cnblogs.com/wyf-love-dch/p/11546610.html
Copyright © 2020-2023  润新知