diff --git a/src/main/java/com/lin/App.java b/src/main/java/com/lin/App.java index 1133952050327f6237c770ee4b996fac7e8f0222..a0e9c12722dff1b6b9f1778f597ec61cb03a092c 100644 --- a/src/main/java/com/lin/App.java +++ b/src/main/java/com/lin/App.java @@ -1,21 +1,17 @@ package com.lin; + +import org.apache.commons.codec.binary.StringUtils; + +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; /** * Hello Utils! */ public class App { - public static void main(String[] args) { - - System.out.println("Hello Utils"); - Map m = new HashMap<>(); - m.put("ss", "ghjk"); - m.put("ss", 23456); - - Object s = m.get("s"); - } -} +} \ No newline at end of file diff --git a/src/main/java/com/lin/enums/StatusCode.java b/src/main/java/com/lin/enums/StatusCode.java new file mode 100644 index 0000000000000000000000000000000000000000..dadd128b86274d9faaf17b1ea716a04422562120 --- /dev/null +++ b/src/main/java/com/lin/enums/StatusCode.java @@ -0,0 +1,34 @@ +package com.lin.enums; + +public enum StatusCode { + + + MIX_SORT(-1, "小到大"), + MAX_SORT(1, "大到小"), + EQUAL(0, "相等"); + + + int code; + String desc; + + StatusCode(int code, String desc) { + this.code = code; + this.desc = desc; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/src/main/java/com/lin/sort/BubbleSort.java b/src/main/java/com/lin/sort/BubbleSort.java new file mode 100644 index 0000000000000000000000000000000000000000..2bbfa36e6f0d666eb880e0aecdd32c843c1e7f2f --- /dev/null +++ b/src/main/java/com/lin/sort/BubbleSort.java @@ -0,0 +1,61 @@ +package com.lin.sort; + +import com.lin.enums.StatusCode; +import com.lin.sort.util.SortUtil; + +/** + * 冒泡排序 + *

O(n)~O(n^2)~O(n^2)

+ * 稳定 + */ +public class BubbleSort { + + + /** + * 冒泡排序 + * + * @param array + * @param statusCode + */ + public static void bubbleSorted(int[] array, StatusCode statusCode) { + for (int i = 0; i < array.length; i++) { + for (int j = 0; j < array.length; j++) { + int falg = SortUtil.compare(array[i], array[j]); + //可修改排序方向 + if (falg == statusCode.getCode()) { + SortUtil.swap(array, i, j); + } + } + } + } + + + /** + * 鸡尾酒排序 + * + * @param array + * @param n + */ + public static void CocktailSort(int[] array, int n) { + int left = 0; // 初始化边界 + int right = n - 1; + while (left < right) { + for (int i = left; i < right; i++) // 前半轮,将最大元素放到后面 + { + if (array[i] > array[i + 1]) { + SortUtil.swap(array, i, i + 1); + } + } + right--; + for (int i = right; i > left; i--) // 后半轮,将最小元素放到前面 + { + if (array[i - 1] > array[i]) { + SortUtil.swap(array, i - 1, i); + } + } + left++; + } + } + + +} diff --git a/src/main/java/com/lin/sort/BucketSort.java b/src/main/java/com/lin/sort/BucketSort.java new file mode 100644 index 0000000000000000000000000000000000000000..9dab05fe57dbc920f34946ba014ba0bb56183bcc --- /dev/null +++ b/src/main/java/com/lin/sort/BucketSort.java @@ -0,0 +1,86 @@ +package com.lin.sort; + +import com.lin.enums.StatusCode; + +import java.util.Arrays; + +public class BucketSort { + + + /** + * 桶排序 + * + * @param sourceArray + * @return + * @throws Exception + */ + public static int[] bucketSorted(int[] sourceArray) { + // 对 arr 进行拷贝,不改变参数内容 + int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); + + return bucketSort(arr, 5); + } + + /** + * 桶排序 + * + * @param arr + * @param bucketSize + * @return + * @throws Exception + */ + private static int[] bucketSort(int[] arr, int bucketSize) { + if (arr.length == 0) { + return arr; + } + + int minValue = arr[0]; + int maxValue = arr[0]; + for (int value : arr) { + if (value < minValue) { + minValue = value; + } else if (value > maxValue) { + maxValue = value; + } + } + + int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1; + int[][] buckets = new int[bucketCount][0]; + + // 利用映射函数将数据分配到各个桶中 + for (int i = 0; i < arr.length; i++) { + int index = (int) Math.floor((arr[i] - minValue) / bucketSize); + buckets[index] = arrAppend(buckets[index], arr[i]); + } + + int arrIndex = 0; + for (int[] bucket : buckets) { + if (bucket.length <= 0) { + continue; + } + // 对每个桶进行排序,这里使用了插入排序 + + InsertionSort.insertionSorted(bucket, StatusCode.MIX_SORT); + +// bucket = insertSort.sort(bucket); + for (int value : bucket) { + arr[arrIndex++] = value; + } + } + + return arr; + } + + /** + * 自动扩容,并保存数据 + * + * @param arr + * @param value + */ + private static int[] arrAppend(int[] arr, int value) { + arr = Arrays.copyOf(arr, arr.length + 1); + arr[arr.length - 1] = value; + return arr; + } + +} diff --git a/src/main/java/com/lin/sort/CountingSort.java b/src/main/java/com/lin/sort/CountingSort.java new file mode 100644 index 0000000000000000000000000000000000000000..f000a3a4f4f9d8031f78879a583809c43b63fa9d --- /dev/null +++ b/src/main/java/com/lin/sort/CountingSort.java @@ -0,0 +1,66 @@ +package com.lin.sort; + +import java.util.Arrays; + +/** + * 计数排序 + */ +public class CountingSort { + + + /** + * 计数排序 + * + * @param sourceArray + * @return 返回排序后的数组 + */ + public static int[] countingsorted(int[] sourceArray) { + // 对 arr 进行拷贝,不改变参数内容 + int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); + + int maxValue = getMaxValue(arr); + + return sort(arr, maxValue); + } + + /** + * 统计排序 + * + * @param arr + * @param maxValue + * @return + */ + private static int[] sort(int[] arr, int maxValue) { + int bucketLen = maxValue + 1; + int[] bucket = new int[bucketLen]; + + for (int value : arr) { + bucket[value]++; + } + + int sortedIndex = 0; + for (int j = 0; j < bucketLen; j++) { + while (bucket[j] > 0) { + arr[sortedIndex++] = j; + bucket[j]--; + } + } + return arr; + } + + /** + * 获取最大值 + * + * @param arr + * @return + */ + private static int getMaxValue(int[] arr) { + int maxValue = arr[0]; + for (int value : arr) { + if (maxValue < value) { + maxValue = value; + } + } + return maxValue; + } +} diff --git a/src/main/java/com/lin/sort/HeapSort.java b/src/main/java/com/lin/sort/HeapSort.java new file mode 100644 index 0000000000000000000000000000000000000000..6ab5f7f907cd86e490642c715394e94b697eb9e7 --- /dev/null +++ b/src/main/java/com/lin/sort/HeapSort.java @@ -0,0 +1,70 @@ +package com.lin.sort; + +import com.lin.enums.StatusCode; +import com.lin.sort.util.SortUtil; + +/** + * 堆排序 + *

O(nlogn)~O(nlogn)~O(nlogn)

+ * 不稳定 + */ +public class HeapSort { + + /** + * 堆排序 + * + * @param array + * @param statusCode + */ + public static void heapSorted(int[] array, StatusCode statusCode) { + int heap_size = buildHeap(array, array.length, statusCode); // 建立一个最大堆 + while (heap_size > 1) { // 堆(无序区)元素个数大于1,未完成排序 + // 将堆顶元素与堆的最后一个元素互换,并从堆中去掉最后一个元素 + // 此处交换操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法 + SortUtil.swap(array, 0, --heap_size); + heapify(array, 0, heap_size, statusCode); // 从新的堆顶元素开始向下进行堆调整,时间复杂度O(logn) + } + } + + + /** + * 堆结构调整 + * + * @param array + * @param i + * @param size + */ + private static void heapify(int[] array, int i, int size, StatusCode statusCode) // 从A[i]向下进行堆调整 + { + int left_child = 2 * i + 1; // 左孩子索引 + int right_child = 2 * i + 2; // 右孩子索引 + int max = i; // 选出当前结点与其左右孩子三者之中的最大值 + if (left_child < size && statusCode.getCode() == SortUtil.compare(array[max], array[left_child])) +// if (left_child < size && array[left_child] > array[max]) + max = left_child; + if (right_child < size && statusCode.getCode() == SortUtil.compare(array[max], array[right_child])) +// if (right_child < size && array[right_child] > array[max]) + max = right_child; + if (max != i) { + SortUtil.swap(array, i, max); // 把当前结点和它的最大(直接)子节点进行交换 + heapify(array, max, size, statusCode); // 递归调用,继续从当前结点向下进行堆调整 + } + } + + /** + * 构造堆 + * + * @param array + * @param n + * @return + */ + private static int buildHeap(int[] array, int n, StatusCode statusCode) // 建堆,时间复杂度O(n) + { + int heap_size = n; + for (int i = heap_size / 2 - 1; i >= 0; i--) // 从每一个非叶结点开始向下进行堆调整 + heapify(array, i, heap_size, statusCode); + return heap_size; + } + + +} diff --git a/src/main/java/com/lin/sort/InsertionSort.java b/src/main/java/com/lin/sort/InsertionSort.java new file mode 100644 index 0000000000000000000000000000000000000000..f19c696bf14a8d15a0fc80c1b4d34d19fe5ff3ed --- /dev/null +++ b/src/main/java/com/lin/sort/InsertionSort.java @@ -0,0 +1,66 @@ +package com.lin.sort; + +import com.lin.enums.StatusCode; +import com.lin.sort.util.SortUtil; + +/** + * 插入排序 + *

O(n)~O(n^2)~O(n^2)

+ * 稳定 + */ +public class InsertionSort { + + + /** + * 插入排序 + * + * @param array + * @param statusCode + */ + public static void insertionSorted(int[] array, StatusCode statusCode) { + //默认第0个是排好序的,i以前的排好序 + for (int i = 1; i < array.length; i++) { + int get = array[i]; + int j = i - 1; + //从当前位值倒序往前查找 + while (j >= 0 && statusCode.getCode() == SortUtil.compare(get, array[j])) { + array[j + 1] = array[j]; + j--; + } + //不满足比较条件时放在位置的右边 + array[j + 1] = get; + } + + } + + /** + * 二分插入排序 + * + * @param array + * @param statusCode + */ + public static void insertionSortedDichotomy(int[] array, StatusCode statusCode) { + for (int i = 1; i < array.length; i++) { + int get = array[i]; + int left = 0; + int right = i - 1; + //二分查找数据所处的位置,也是在之前的队列中 + while (left <= right) + { + int mid = (left + right) / 2; + if (statusCode.getCode() == SortUtil.compare(get,array[mid])) +// if (array[mid] > get) + right = mid - 1; + else + left = mid + 1; + } + //拿走的是位置i的数据,left之后的往后移动 + for (int j = i - 1; j >= left; j--) + { + array[j + 1] = array[j]; + } + array[left] = get; + } + } + +} diff --git a/src/main/java/com/lin/sort/MergeSort.java b/src/main/java/com/lin/sort/MergeSort.java new file mode 100644 index 0000000000000000000000000000000000000000..5df23b9f949973600d3a134daa4693c69ff8d39e --- /dev/null +++ b/src/main/java/com/lin/sort/MergeSort.java @@ -0,0 +1,89 @@ +package com.lin.sort; + +import com.lin.enums.StatusCode; +import com.lin.sort.util.SortUtil; + +/** + * 归并排序 + *

O(nlogn)~O(nlogn)~O(nlogn)

+ * 稳定 + */ +public class MergeSort { + + + /** + * 非递归归并排序(错误) + * + * @param array + * @param statusCode + */ + public static void mergeSortedIteration(int array[], StatusCode statusCode) { + int left, mid, right; + for (int i = 1; i < array.length; i *= 2) { + left = 0; + while (left + i < array.length) { + mid = left + i - 1; + right = mid + 1 < array.length ? mid + 1 : array.length - 1; + merge(array, statusCode, left, mid, right); + left = mid + 1; + } + } + } + + + /** + * 递归使用归并排序 + * + * @param array + * @param statusCode + * @param left + * @param right + */ + public static void mergeSortedRecursion(int[] array, StatusCode statusCode, int left, int right) { + if (left == right) + return; + int mid = (left + right) / 2; + //前半段数组归并 + mergeSortedRecursion(array, statusCode, left, mid); + //后半段数组归并 + mergeSortedRecursion(array, statusCode, mid + 1, right); + //归并合并 + merge(array, statusCode, left, mid, right); + } + + /** + * 数组合并 + * + * @param array + * @param statusCode + * @param left + * @param mid + * @param right + */ + private static void merge(int[] array, StatusCode statusCode, int left, int mid, int right) { + int len = right - left + 1; + int[] temp = new int[len]; + int index = 0; + //前半段数组起始 + int i = left; + //后半段数组起始 + int j = mid + 1; + //两组数据归并操作 + while (i <= mid && j <= right) { + temp[index++] = statusCode.getCode() == SortUtil.compare(array[i], array[j]) ? array[i++] : array[j++]; + } + //上面的循环无法将两个子数组的数据全部循环到 + while (i <= mid) { + temp[index++] = array[i++]; + } + while (j <= right) { + temp[index++] = array[j++]; + } + //数据放入原 + int tindex = 0; + while (tindex < temp.length) { + array[left++] = temp[tindex++]; + } + + } +} diff --git a/src/main/java/com/lin/sort/QuickSort.java b/src/main/java/com/lin/sort/QuickSort.java new file mode 100644 index 0000000000000000000000000000000000000000..f4f76c4e3f82b72927e0890ef89c9d6d09fa599d --- /dev/null +++ b/src/main/java/com/lin/sort/QuickSort.java @@ -0,0 +1,52 @@ +package com.lin.sort; + +import com.lin.enums.StatusCode; +import com.lin.sort.util.SortUtil; + +/** + * 快速排序 + *

O(nlogn)~O(nlogn)~O(n^2)

+ * 不稳定 + */ +public class QuickSort { + + + /** + * 分治块 + * + * @param array + * @param left + * @param right + * @param statusCode + * @return + */ + private static int partition(int[] array, int left, int right, StatusCode statusCode) // 划分函数 + { + int pivot = array[right]; // 这里每次都选择最后一个元素作为基准 + int tail = left - 1; // tail为小于基准的子数组最后一个元素的索引 + for (int i = left; i < right; i++) // 遍历基准以外的其他元素 + { + if (SortUtil.compare(pivot, array[i]) == 0 || !(statusCode.getCode() == SortUtil.compare(pivot, array[i]))) //会破环稳定性 +// if (array[i] <= pivot) // 把小于等于基准的元素放到前一个子数组末尾 + { + SortUtil.swap(array, ++tail, i); + } + } + SortUtil.swap(array, tail + 1, right); // 最后把基准放到前一个子数组的后边,剩下的子数组既是大于基准的子数组 + // 该操作很有可能把后面元素的稳定性打乱,所以快速排序是不稳定的排序算法 + return tail + 1; // 返回基准的索引 + } + + /** + * 快速排序 + */ + public static void quickSorted(int[] array, int left, int right, StatusCode statusCode) { + if (left >= right) + return; + int pivot_index = partition(array, left, right, statusCode); // 基准的索引 + quickSorted(array, left, pivot_index - 1, statusCode); + quickSorted(array, pivot_index + 1, right, statusCode); + } + + +} diff --git a/src/main/java/com/lin/sort/RadixSort.java b/src/main/java/com/lin/sort/RadixSort.java new file mode 100644 index 0000000000000000000000000000000000000000..6c66253f38846e2914347e58d43f9949e2812eca --- /dev/null +++ b/src/main/java/com/lin/sort/RadixSort.java @@ -0,0 +1,107 @@ +package com.lin.sort; + +import java.util.Arrays; + +/** + * 基数排序 + */ +public class RadixSort { + + + /** + * 基数排序 + * + * @param sourceArray + * @return + */ + public static int[] radixSorted(int[] sourceArray) { + // 对 arr 进行拷贝,不改变参数内容 + int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); + + int maxDigit = getMaxDigit(arr); + return radixSort(arr, maxDigit); + } + + /** + * 获取最高位数 + * + * @param arr + * @return + */ + private static int getMaxDigit(int[] arr) { + int maxValue = getMaxValue(arr); + return getNumLenght(maxValue); + } + + /** + * 获取最大值 + * + * @param arr + * @return + */ + private static int getMaxValue(int[] arr) { + int maxValue = arr[0]; + for (int value : arr) { + if (maxValue < value) { + maxValue = value; + } + } + return maxValue; + } + + protected static int getNumLenght(long num) { + if (num == 0) { + return 1; + } + int lenght = 0; + for (long temp = num; temp != 0; temp /= 10) { + lenght++; + } + return lenght; + } + + /** + * 基数排序 + * + * @param arr + * @param maxDigit + * @return + */ + private static int[] radixSort(int[] arr, int maxDigit) { + int mod = 10; + int dev = 1; + + for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) { + // 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10) + int[][] counter = new int[mod * 2][0]; + + for (int j = 0; j < arr.length; j++) { + int bucket = ((arr[j] % mod) / dev) + mod; + counter[bucket] = arrayAppend(counter[bucket], arr[j]); + } + + int pos = 0; + for (int[] bucket : counter) { + for (int value : bucket) { + arr[pos++] = value; + } + } + } + + return arr; + } + + /** + * 自动扩容,并保存数据 + * + * @param arr + * @param value + */ + private static int[] arrayAppend(int[] arr, int value) { + arr = Arrays.copyOf(arr, arr.length + 1); + arr[arr.length - 1] = value; + return arr; + } + + +} diff --git a/src/main/java/com/lin/sort/SelectionSort.java b/src/main/java/com/lin/sort/SelectionSort.java new file mode 100644 index 0000000000000000000000000000000000000000..3b6e7d3db5ac2c5d49bb47a5122dc585c63b5879 --- /dev/null +++ b/src/main/java/com/lin/sort/SelectionSort.java @@ -0,0 +1,42 @@ +package com.lin.sort; + +import com.lin.enums.StatusCode; +import com.lin.sort.util.SortUtil; + +/** + * 选择排序 + *

O(n^2)~O(n^2)~O(n^2)

+ * 不稳定 + */ +public class SelectionSort { + + + /** + * 选择排序 + * + * @param array + * @param statusCode + */ + public static void selectionSorted(int[] array, StatusCode statusCode) { + //确定最小的位置 + for (int i = 0; i < array.length; i++) { + int min = i; + //确定最小的位置存放的数据 + for (int j = i + 1; j < array.length; j++) { + //用标志为查出为排序队列中最小/大的 + if (statusCode.getCode() == SortUtil.compare(array[j], array[min])) { + min = j; + } + } + //将最小的放在最前面 + if (min != i) { + SortUtil.swap(array, i, min); + } + + } + + + } + + +} diff --git a/src/main/java/com/lin/sort/ShellSort.java b/src/main/java/com/lin/sort/ShellSort.java new file mode 100644 index 0000000000000000000000000000000000000000..9bc773920f250d02b42ea2a516efc51a1bd078f7 --- /dev/null +++ b/src/main/java/com/lin/sort/ShellSort.java @@ -0,0 +1,44 @@ +package com.lin.sort; + +import com.lin.enums.StatusCode; +import com.lin.sort.util.SortUtil; + +/** + * 希尔排序 + *

O(n^1.3)~O(nlogn)~O(n^2)~O(n^2)

+ * 不稳定 + */ +public class ShellSort { + + + /** + * 希尔排序 + * + * @param array + * @param statusCode + */ + public static void shellSorted(int[] array, StatusCode statusCode) { + int shell = 0; + //寻找最大的希尔值 + while (shell <= array.length) { + shell = shell * 3 + 1; + } + //通过希尔来降低排序复杂度 + while (shell >= 1) { + //确定希尔值后,内部使用呢直接插入排序 + for (int i = shell; i < array.length; i++) { + int j = i - shell; + int get = array[i]; + while (j >= 0 && statusCode.getCode() == SortUtil.compare(get, array[j])) { + array[j + shell] = array[j]; + j = j - shell; + } + array[j + shell] = get; + } + shell = (shell - 1) / 3; + } + + + } + +} diff --git a/src/main/java/com/lin/sort/util/SortUtil.java b/src/main/java/com/lin/sort/util/SortUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..331e81f7af337e46802c2723ffef5e6fe3abb77b --- /dev/null +++ b/src/main/java/com/lin/sort/util/SortUtil.java @@ -0,0 +1,38 @@ +package com.lin.sort.util; + +/** + * 排序工具 + */ +public class SortUtil { + + /** + * 交换 + * + * @param array + * @param a + * @param b + */ + public static void swap(int[] array, int a, int b) { + int temp = array[a]; + array[a] = array[b]; + array[b] = temp; + } + + /** + * 比较器 + * + * @param a + * @param b + * @return + */ + public static int compare(int a, int b) { + if (a > b) { + return 1; + } else if (a < b) { + return -1; + } else { + return 0; + } + } + +} diff --git a/src/main/java/com/lin/tree/nome/BSTree.java b/src/main/java/com/lin/tree/nome/BSTree.java new file mode 100644 index 0000000000000000000000000000000000000000..362584caf6232366c777a3ae5da5baabc8afb703 --- /dev/null +++ b/src/main/java/com/lin/tree/nome/BSTree.java @@ -0,0 +1,312 @@ +package com.lin.tree.nome; + +import lombok.Data; + +/** + * 二叉搜索树 + * + * @param + */ +public class BSTree> { + + + private BSTNode mRoot; + + + @Data + public class BSTNode> { + T key; + BSTNode left; + BSTNode right; + BSTNode parent; + + public BSTNode() { + super(); + } + + public BSTNode(T key, BSTNode left, BSTNode right, BSTNode parent) { + this.key = key; + this.left = left; + this.right = right; + this.parent = parent; + } + } + + /** + * 二叉搜索树递归查找 + * + * @param x + * @param key + * @return + */ + private BSTNode search(BSTNode x, T key) { + if (x == null) + return x; + + int cmp = key.compareTo(x.key); + if (cmp < 0) + return search(x.left, key); + else if (cmp > 0) + return search(x.right, key); + else + return x; + } + + public BSTNode search(T key) { + return search(mRoot, key); + } + + /** + * 二叉搜索树非递归查找 + * + * @param x + * @param key + * @return + */ + private BSTNode iterativeSearch(BSTNode x, T key) { + while (x != null) { + int cmp = key.compareTo(x.key); + + if (cmp < 0) + x = x.left; + else if (cmp > 0) + x = x.right; + else + return x; + } + + return x; + } + + public BSTNode iterativeSearch(T key) { + return iterativeSearch(mRoot, key); + } + + /** + * 查找最大节点 + * + * @param tree + * @return + */ + private BSTNode maximum(BSTNode tree) { + if (tree == null) + return null; + + while (tree.right != null) + tree = tree.right; + return tree; + } + + public T maximum() { + BSTNode p = maximum(mRoot); + if (p != null) + return p.key; + + return null; + } + + /** + * 查找最小节点 + * + * @param tree + * @return + */ + private BSTNode minimum(BSTNode tree) { + if (tree == null) + return null; + + while (tree.left != null) + tree = tree.left; + return tree; + } + + public T minimum() { + BSTNode p = minimum(mRoot); + if (p != null) + return p.key; + + return null; + } + + /** + * 查找前驱节点 + * + * @param x + * @return + */ + public BSTNode predecessor(BSTNode x) { + // 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。 + if (x.left != null) + return maximum(x.left); + + // 如果x没有左孩子。则x有以下两种可能: + // (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。 + // (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。 + BSTNode y = x.parent; + while ((y != null) && (x == y.left)) { + x = y; + y = y.parent; + } + + return y; + } + + /** + * 查找后继节点 + * + * @param x + * @return + */ + public BSTNode successor(BSTNode x) { + // 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。 + if (x.right != null) + return minimum(x.right); + + // 如果x没有右孩子。则x有以下两种可能: + // (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。 + // (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。 + BSTNode y = x.parent; + while ((y != null) && (x == y.right)) { + x = y; + y = y.parent; + } + + return y; + } + + /** + * 将节点插入二叉树 + * + * @param bst + * @param z + */ + private void insert(BSTree bst, BSTNode z) { + int cmp; + BSTNode y = null; + BSTNode x = bst.mRoot; + + // 查找z的插入位置 + while (x != null) { + y = x; + cmp = z.key.compareTo(x.key); + if (cmp < 0) + x = x.left; + else + x = x.right; + } + + z.parent = y; + if (y == null) + bst.mRoot = z; + else { + cmp = z.key.compareTo(y.key); + if (cmp < 0) + y.left = z; + else + y.right = z; + } + } + + public void insert(T key) { + BSTNode z = new BSTNode(key, null, null, null); + + // 如果新建结点失败,则返回。 + if (z != null) + insert(this, z); + } + + /** + * 删除节点并返回 + * + * @param bst + * @param z + * @return + */ + private BSTNode remove(BSTree bst, BSTNode z) { + BSTNode x = null; + BSTNode y = null; + + if ((z.left == null) || (z.right == null)) + y = z; + else + y = successor(z); + + if (y.left != null) + x = y.left; + else + x = y.right; + + if (x != null) + x.parent = y.parent; + + if (y.parent == null) + bst.mRoot = x; + else if (y == y.parent.left) + y.parent.left = x; + else + y.parent.right = x; + + if (y != z) + z.key = y.key; + + return y; + } + + public void remove(T key) { + BSTNode z, node; + + if ((z = search(mRoot, key)) != null) + if ((node = remove(this, z)) != null) + node = null; + } + + /** + * 打印二叉搜索树 + * + * @param tree + * @param key + * @param direction + */ + private void print(BSTNode tree, T key, int direction) { + + if (tree != null) { + + if (direction == 0) // tree是根节点 + System.out.printf("%2d is root\n", tree.key); + else // tree是分支节点 + System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction == 1 ? "right" : "left"); + + print(tree.left, tree.key, -1); + print(tree.right, tree.key, 1); + } + } + + public void print() { + if (mRoot != null) + print(mRoot, mRoot.key, 0); + } + + + /** + * 销毁二叉树 + * + * @param tree + */ + private void destroy(BSTNode tree) { + if (tree == null) + return; + + if (tree.left != null) + destroy(tree.left); + if (tree.right != null) + destroy(tree.right); + + tree = null; + } + + public void clear() { + destroy(mRoot); + mRoot = null; + } + +} diff --git a/src/main/java/com/lin/tree/nome/Tree.java b/src/main/java/com/lin/tree/nome/Tree.java new file mode 100644 index 0000000000000000000000000000000000000000..91694a48ba2fa75eea4a4a2bad42b7a5354e1eac --- /dev/null +++ b/src/main/java/com/lin/tree/nome/Tree.java @@ -0,0 +1,186 @@ +package com.lin.tree.nome; + + +import lombok.Data; + +import java.util.Queue; +import java.util.Stack; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * 普通二叉树 + */ +public class Tree { + + /** + * 递归实现前序遍历 + * + * @param node + */ + public void preOrderTraverse(Node node) { + if (node != null) { + System.out.println(node.getValue()); + preOrderTraverse(node.getLeft()); + preOrderTraverse(node.getRight()); + } + } + + /** + * 非递归实现的前序遍历 + * + * @param root + */ + public void nrPreOrderTraverse(Node root) { + //借助栈实现 + Stack> stack = new Stack>(); + Node node = root; + while (node != null || !stack.isEmpty()) { + + while (node != null) { + System.out.println(node.getValue()); + stack.push(node); + node = node.getLeft(); + } + node = stack.pop(); + node = node.getRight(); + } + + } + + /** + * 递归实现的中序遍历 + * + * @param node + */ + public void inOrderTraverse(Node node) { + if (node != null) { + inOrderTraverse(node.getLeft()); + System.out.println(node.getValue()); + inOrderTraverse(node.getRight()); + } + } + + /** + * 非递归实现的中序遍历 + * + * @param root + */ + public void nrInOrderTraverse(Node root) { + Stack> stack = new Stack>(); + Node node = root; + while (node != null || !stack.isEmpty()) { + while (node != null) { + stack.push(node); + node = node.getLeft(); + } + node = stack.pop(); + System.out.println(node.getValue()); + node = node.getRight(); + } + } + + /** + * 递归实现的后续遍历 + * + * @param node + */ + public void postOrderTraverse(Node node) { + if (node != null) { + postOrderTraverse(node.getLeft()); + postOrderTraverse(node.getRight()); + System.out.println(node.getValue()); + } + } + + /** + * 非递归实现的后续遍历 + * + * @param root + */ + public void nrPostOrderTraverse(Node root) { + + Stack> stack = new Stack>(); + Node node = root; + Node preNode = null;//表示最近一次访问的节点 + + while (node != null || !stack.isEmpty()) { + while (node != null) { + stack.push(node); + node = node.getLeft(); + } + + node = stack.peek(); + + if (node.getRight() == null || node.getRight() == preNode) { + System.out.println(node.getValue()); + node = stack.pop(); + preNode = node; + node = null; + } else { + node = node.getRight(); + } + } + } + + /** + * 借助队列实现的层序遍历 + * + * @param node + */ + public void levelTraverse(Node node) { + //借助队列实现 + Queue> queue = new LinkedBlockingQueue>(); + queue.add(node); + while (!queue.isEmpty()) { + + Node temp = queue.poll(); + if (temp != null) { + System.out.println(temp.getValue()); + queue.add(temp.getLeft()); + queue.add(temp.getRight()); + } + } + } + + /** + * 获取树的深度 + * + * @param node + * @return + */ + private Integer getHeight(Node node) { + if (node == null) + return 0; + else { + int left = getHeight(node.getLeft()); + int right = getHeight(node.getRight()); + return left > right ? left + 1 : right + 1;//左子树 右子树最深的,再加上父节点本身深度1 + } + } + + /** + * 获取节点数量 + * + * @param node + * @return + */ + private Integer getSize(Node node) { + if (node == null) + return 0; + else { + int leftSize = getSize(node.getLeft()); + int rightSize = getSize(node.getRight()); + return leftSize + rightSize + 1; + } + } + + + @Data + public class Node { + Node left; + Node right; + T value; + } + + +} diff --git a/src/main/java/com/lin/tree/nome/avltree/AVLTree1.java b/src/main/java/com/lin/tree/nome/avltree/AVLTree1.java new file mode 100644 index 0000000000000000000000000000000000000000..4a13540a9e710f21e2608a16646e8d6d2467387e --- /dev/null +++ b/src/main/java/com/lin/tree/nome/avltree/AVLTree1.java @@ -0,0 +1,297 @@ +package com.lin.tree.nome.avltree; + +import java.util.Comparator; + +public class AVLTree1 { + + private static class Node { + int h; + E element; + Node left; + Node right; + //由于java中不像C语言那样有二级指针的概念,所以添加一个父类的引用,方便程序编写 + Node parent; + + public Node(E element, int h, Node left, Node right, Node parent) { + this.element = element; + this.h = h; + this.left = left; + this.right = right; + this.parent = parent; + } + } + + private Node root;//指向伪根节点的引用 + private int size = 0;//节点个数 + Comparator cmp;//节点大小的比较器 + + //如果调用了不带参数的构造函数,则使用该内部类作为比较器, + //但此时泛型E需要继承Comparable接口,否则运行时会抛出异常 + private static class Cmp implements Comparator { + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public int compare(T e1, T e2) { + return ((Comparable) e1).compareTo(e2); + } + + } + + //带比较器的构造函数 + public AVLTree1(Comparator cmp) { + if (cmp == null) { + throw new IllegalArgumentException(); + } + this.cmp = cmp; + //创建一个伪根节点,该节点的右子支才是真正的AVL树的根 + //使用伪根节点节点的目的是,对插入和删除操作递归的形式能够统一 + root = new Node(null, -1, null, null, null); + } + + //不带比较器的构造函数 + public AVLTree1() { + this.cmp = new Cmp(); + root = new Node(null, -1, null, null, null); + } + + //如果树中节点有变动,从底向上逐级调用该函数,可以更新节点的高度 + private int getHight(Node x) { + if (x == null) { + return 0; + } else { + return x.h; + } + } + + //求某个节点作为根时,该子树的最小值 + private E treeMin(Node x) { + while (x.left != null) { + x = x.left; + } + return x.element; + } + + public int size() { + return size; + } + + //先根遍历,调试时使用 + public void preorderTraverse() { + if (root != null) { + preorderTraverse0(root.right); + } + } + + private void preorderTraverse0(Node x) { + if (x != null) { + System.out.print(x.element + " "); + if (x.left != null) { + System.out.print(x.left.element + " "); + } else { + System.out.print("null "); + } + + if (x.right != null) { + System.out.print(x.right.element + " "); + } else { + System.out.print("null "); + } + System.out.println(); + preorderTraverse0(x.left); + preorderTraverse0(x.right); + } + } + + //逆时针旋转(左旋),参数表示轴节点 + private void antiClockwiseRotate(Node X) { + Node P = X.parent; + Node XR = X.right; + if (P.left == X) { + P.left = XR; + } else { + P.right = XR; + } + XR.parent = P; + + X.right = XR.left; + if (XR.left != null) { + XR.left.parent = X; + } + + XR.left = X; + X.parent = XR; + + //旋转后要更新这两个节点的高度 + X.h = Math.max(getHight(X.left), getHight(X.right)) + 1; + XR.h = Math.max(getHight(XR.left), getHight(XR.right)) + 1; + } + + //顺时针旋转(右旋),参数表示轴节点 + private void clockwistRotate(Node X) { + Node P = X.parent; + Node XL = X.left; + if (P.left == X) { + P.left = XL; + } else { + P.right = XL; + } + XL.parent = P; + + X.left = XL.right; + if (XL.right != null) { + XL.right.parent = X; + } + + XL.right = X; + X.parent = XL; + + //旋转后要更新这两个节点的高度 + X.h = Math.max(getHight(X.left), getHight(X.right)) + 1; + XL.h = Math.max(getHight(XL.left), getHight(XL.right)) + 1; + } + + // + public void insert(E e) { + insert0(root.right, e); + } + + private void insert0(Node x, E e) { + if (x == null) { + root.right = new Node(e, 1, null, null, root);//根节点 + size++; + return; + } + + if (cmp.compare(e, x.element) > 0) { + if (x.right != null) { + insert0(x.right, e); + int lh = getHight(x.left); + int rh = getHight(x.right); + if (rh - lh == 2) { + if (cmp.compare(e, x.right.element) > 0) { + antiClockwiseRotate(x); + } else { + clockwistRotate(x.right); + antiClockwiseRotate(x); + } + } + } else { + size++; + x.right = new Node(e, 1, null, null, x); + } + } else if (cmp.compare(e, x.element) < 0) { + if (x.left != null) { + insert0(x.left, e); + int lh = getHight(x.left); + int rh = getHight(x.right); + if (lh - rh == 2) { + if (cmp.compare(e, x.left.element) < 0) { + clockwistRotate(x); + } else { + antiClockwiseRotate(x.left); + clockwistRotate(x); + } + } + } else { + size++; + x.left = new Node(e, 1, null, null, x); + } + } else { + //元素已存在,我们用新的元素更新旧, + //compare返回值等于0,并不表示两个对象完全相等 + x.element = e; + } + x.h = Math.max(getHight(x.left), getHight(x.right)) + 1; + } + + public boolean delete(E e) { + return delete0(root.right, e); + } + + //返回值表示是否删除成功 + private boolean delete0(Node x, E e) { + if (x == null) {//没有找到待删除的元素 + return false; + } + + if (cmp.compare(e, x.element) > 0) { + boolean reval = delete0(x.right, e); + if (reval == false) { + return false; + } + + int lh = getHight(x.left); + int rh = getHight(x.right); + if (lh - rh == 2) { + if (getHight(x.left.left) > getHight(x.left.right)) { + clockwistRotate(x); + } else { + antiClockwiseRotate(x.left); + clockwistRotate(x); + } + } + } else if (cmp.compare(e, x.element) < 0) { + boolean reval = delete0(x.left, e); + if (reval == false) { + return false; + } + + int lh = getHight(x.left); + int rh = getHight(x.right); + if (rh - lh == 2) { + if (getHight(x.right.right) > getHight(x.right.left)) { + antiClockwiseRotate(x); + } else { + clockwistRotate(x.right); + antiClockwiseRotate(x); + } + } + } else {//找到待删除的元素 + Node P = x.parent; + + if (x.left == null) {//左子支为空,可直接删除,在这一层一定不需要旋转 + size--; + if (P.left == x) { + P.left = x.right; + if (P.left != null) { + P.left.parent = P; + } + } else { + P.right = x.right; + if (P.right != null) { + P.right.parent = P; + } + } + } else if (x.right == null) {//右子支为空,可直接删除,在这一层一定不需要旋转 + size--; + if (P.left == x) { + P.left = x.left; + if (P.left != null) { + P.left.parent = P; + } + } else { + P.right = x.left; + if (P.right != null) { + P.right.parent = P; + } + } + } else {//找到待删除的节点,用后继节点代替,然后删除后继节点 + E nextVal = treeMin(x.right); + x.element = nextVal; + delete0(x.right, nextVal); + int lh = getHight(x.left); + int rh = getHight(x.right); + if (lh - rh == 2) { + if (getHight(x.left.left) > getHight(x.left.right)) { + clockwistRotate(x); + } else { + antiClockwiseRotate(x.left); + clockwistRotate(x); + } + } + } + } + x.h = Math.max(getHight(x.left), getHight(x.right)) + 1; + return true; + } + +} diff --git a/src/main/java/com/lin/tree/nome/avltree/AVLTree2.java b/src/main/java/com/lin/tree/nome/avltree/AVLTree2.java new file mode 100644 index 0000000000000000000000000000000000000000..4b2cc0e01892029b10a0b05813105dab90a463d2 --- /dev/null +++ b/src/main/java/com/lin/tree/nome/avltree/AVLTree2.java @@ -0,0 +1,199 @@ +package com.lin.tree.nome.avltree; + +//AVL树的节点类 +class AVLNode { + T element; + AVLNode left; + AVLNode right; + int height;//记录高度 + + //构造器 + public AVLNode(T theElement) { + this(theElement, null, null); + element = theElement; + } + + public AVLNode(T theElement, AVLNode left, AVLNode right) { + this.element = theElement; + this.left = left; + this.right = right; + this.height = 0; + } +} + +//AVL树 +public class AVLTree2 { + //私有属性 + private AVLNode root;//根节点 + + private int height(AVLNode t) { + return t == null ? -1 : t.height; + } + + //构造方法 + AVLTree2() { + this.root = null; + } + + //插入操作 + public void insert(T x) { + this.root = insert(x, root); + } + + //删除操作 + public void remove(T x) { + this.root = remove(x, root); + } + + //中序打印操作 + public void infPrintTree() { + infPrintTree(root); + System.out.println(); + } + + //判断是否是AVL树 + public boolean isAVL() { + return Math.abs(maxDeep(root.right) - maxDeep(root.left)) < 2; + } + + public AVLNode findMax(AVLNode t) { + if (t == null) + throw new RuntimeException("this AVLNode is Empty"); + if (t.right == null) + return t; + return findMax(t.right); + } + + public AVLNode insert(T x, AVLNode t) { + if (t == null)//传入节点为空,则将该节点作为根节点返回 + return new AVLNode<>(x, null, null); + int compareResult = x.compareTo(t.element); + if (compareResult < 0)//传入元素x小于t + t.left = insert(x, t.left); + else if (compareResult > 0)//传入元素x大于t + t.right = insert(x, t.right); + return balance(t); + } + + //重新进行平衡 + public AVLNode balance(AVLNode t) { + if (t == null) + return t; + if (height(t.left) - height(t.right) > 1) {//左插入 + if (height(t.left.left) >= height(t.left.right)) //左左插入 情形1 + t = singleRightRotate(t);//右旋 + else //左右插入 情形2 + t = doubleLeftRightRotate(t);//左右双旋 + } + if (height(t.right) - height(t.left) > 1) {//右插入 + if (height(t.right.right) >= height(t.right.left)) //右右插入 情形3 + t = singleLeftRotate(t);//左旋 + else //右左插入 情形4 + t = doubleRightLeftRotate(t);//右左双旋 + } + t.height = height(t.right) > height(t.left) ? height(t.right) + 1 : height(t.left) + 1; + return t; + } + + //右单旋 + private AVLNode singleRightRotate(AVLNode t) { + System.out.println("进行右旋转==============>>>"); + AVLNode r = t.left; + t.left = r.right; + r.right = t; + t.height = height(t.left) > height(t.right) ? height(t.left) + 1 : height(t.right) + 1; + r.height = height(t.right) > height(r) ? height(t.right) + 1 : height(r) + 1; + return r; + } + + //左单旋 + private AVLNode singleLeftRotate(AVLNode t) { + System.out.println("进行左旋转==============>>>"); + AVLNode r = t.right; + t.right = r.left; + r.left = t; + t.height = height(t.left) > height(t.right) ? height(t.left) + 1 : height(t.right) + 1; + r.height = height(t.left) > height(r) ? height(t.left) + 1 : height(r) + 1; + return r; + } + + //右左双旋 + private AVLNode doubleRightLeftRotate(AVLNode t) { + System.out.println("进行右左双旋==============>>>"); + t.right = singleRightRotate(t.right); + return singleLeftRotate(t); + } + + //左右双旋 + private AVLNode doubleLeftRightRotate(AVLNode t) { + System.out.println("进行左右双旋==============>>>"); + t.left = singleLeftRotate(t.left); + return singleRightRotate(t); + } + + public AVLNode remove(T x, AVLNode t) { + if (t == null)//传入节点为空 + return t; + int compareResult = x.compareTo(t.element); + if (compareResult < 0) + t.left = remove(x, t.left); + else if (compareResult > 0) + t.right = remove(x, t.right); + else if (t.left != null && t.right != null) { //有两个儿子 + t.element = findMax(t.left).element; + remove(t.element, t.left); + } else //单儿子情形 + t = t.left == null ? t.right : t.left; + if (t != null) + t.height = height(t.right) > height(t.left) ? height(t.right) + 1 : height(t.left) + 1; + return balance(t); + } + + public int maxDeep(AVLNode t) { + int dl, dr;//记录左右树的深度 + if (t == null) + return 0; + else { + dl = maxDeep(t.left); + dr = maxDeep(t.right); + } + return dl > dr ? dl + 1 : dr + 1; + } + + + public void infPrintTree(AVLNode t) { + if (t == null) + return; + infPrintTree(t.left); + System.out.print(t.element + " "); + infPrintTree(t.right); + } + +// public static void main(String[] args) { +// AVLTree2 avlT = createAVLTree(); +// System.out.println("是否是AVL树:" + avlT.isAVL()); +// System.out.println("中序打印出该树===>>>"); +// avlT.infPrintTree(); +// avlT.remove(60); +// avlT.insert(35); +// } + + /** + * 50 + * / \ + * 30 60 + * / \ + * 20 40 + * + * @return + */ + private static AVLTree2 createAVLTree() { + AVLTree2 avlT = new AVLTree2(); + avlT.insert(50); + avlT.insert(60); + avlT.insert(30); + avlT.insert(40); + avlT.insert(20); + return avlT; + } +} \ No newline at end of file diff --git a/src/main/java/com/lin/tree/nome/rbtree/RBTree1.java b/src/main/java/com/lin/tree/nome/rbtree/RBTree1.java new file mode 100644 index 0000000000000000000000000000000000000000..0905b7162813a08692b0659f6e96e2c95e14d930 --- /dev/null +++ b/src/main/java/com/lin/tree/nome/rbtree/RBTree1.java @@ -0,0 +1,691 @@ +package com.lin.tree.nome.rbtree; + +/** + * 红黑树 + * @param + */ +public class RBTree1> { + + private RBTNode mRoot; // 根结点 + + private static final boolean RED = false; + private static final boolean BLACK = true; + + public class RBTNode> { + boolean color; // 颜色 + T key; // 关键字(键值) + RBTNode left; // 左孩子 + RBTNode right; // 右孩子 + RBTNode parent; // 父结点 + + public RBTNode(T key, boolean color, RBTNode parent, RBTNode left, RBTNode right) { + this.key = key; + this.color = color; + this.parent = parent; + this.left = left; + this.right = right; + } + + public T getKey() { + return key; + } + + public String toString() { + return ""+key+(this.color==RED?"(R)":"B"); + } + } + + public RBTree1() { + mRoot=null; + } + + private RBTNode parentOf(RBTNode node) { + return node!=null ? node.parent : null; + } + private boolean colorOf(RBTNode node) { + return node!=null ? node.color : BLACK; + } + private boolean isRed(RBTNode node) { + return ((node!=null)&&(node.color==RED)) ? true : false; + } + private boolean isBlack(RBTNode node) { + return !isRed(node); + } + private void setBlack(RBTNode node) { + if (node!=null) + node.color = BLACK; + } + private void setRed(RBTNode node) { + if (node!=null) + node.color = RED; + } + private void setParent(RBTNode node, RBTNode parent) { + if (node!=null) + node.parent = parent; + } + private void setColor(RBTNode node, boolean color) { + if (node!=null) + node.color = color; + } + + /** + * 前序遍历"红黑树" + */ + private void preOrder(RBTNode tree) { + if(tree != null) { + System.out.print(tree.key+" "); + preOrder(tree.left); + preOrder(tree.right); + } + } + + public void preOrder() { + preOrder(mRoot); + } + + /** + * 中序遍历"红黑树" + */ + private void inOrder(RBTNode tree) { + if(tree != null) { + inOrder(tree.left); + System.out.print(tree.key+" "); + inOrder(tree.right); + } + } + + public void inOrder() { + inOrder(mRoot); + } + + + /** + * 后序遍历"红黑树" + */ + private void postOrder(RBTNode tree) { + if(tree != null) + { + postOrder(tree.left); + postOrder(tree.right); + System.out.print(tree.key+" "); + } + } + + public void postOrder() { + postOrder(mRoot); + } + + + /** + * (递归实现)查找"红黑树x"中键值为key的节点 + */ + private RBTNode search(RBTNode x, T key) { + if (x==null) + return x; + + int cmp = key.compareTo(x.key); + if (cmp < 0) + return search(x.left, key); + else if (cmp > 0) + return search(x.right, key); + else + return x; + } + + public RBTNode search(T key) { + return search(mRoot, key); + } + + /** + * (非递归实现)查找"红黑树x"中键值为key的节点 + */ + private RBTNode iterativeSearch(RBTNode x, T key) { + while (x!=null) { + int cmp = key.compareTo(x.key); + + if (cmp < 0) + x = x.left; + else if (cmp > 0) + x = x.right; + else + return x; + } + + return x; + } + + public RBTNode iterativeSearch(T key) { + return iterativeSearch(mRoot, key); + } + + /** + * 查找最小结点:返回tree为根结点的红黑树的最小结点。 + */ + private RBTNode minimum(RBTNode tree) { + if (tree == null) + return null; + + while(tree.left != null) + tree = tree.left; + return tree; + } + + public T minimum() { + RBTNode p = minimum(mRoot); + if (p != null) + return p.key; + + return null; + } + + /** + * 查找最大结点:返回tree为根结点的红黑树的最大结点。 + */ + private RBTNode maximum(RBTNode tree) { + if (tree == null) + return null; + + while(tree.right != null) + tree = tree.right; + return tree; + } + + public T maximum() { + RBTNode p = maximum(mRoot); + if (p != null) + return p.key; + + return null; + } + + /** + * 找结点(x)的后继结点。即,查找"红黑树中数据值大于该结点"的"最小结点"。 + */ + public RBTNode successor(RBTNode x) { + // 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。 + if (x.right != null) + return minimum(x.right); + + // 如果x没有右孩子。则x有以下两种可能: + // (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。 + // (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。 + RBTNode y = x.parent; + while ((y!=null) && (x==y.right)) { + x = y; + y = y.parent; + } + + return y; + } + + /** + * 找结点(x)的前驱结点。即,查找"红黑树中数据值小于该结点"的"最大结点"。 + */ + public RBTNode predecessor(RBTNode x) { + // 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。 + if (x.left != null) + return maximum(x.left); + + // 如果x没有左孩子。则x有以下两种可能: + // (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。 + // (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。 + RBTNode y = x.parent; + while ((y!=null) && (x==y.left)) { + x = y; + y = y.parent; + } + + return y; + } + + /** + * 对红黑树的节点(x)进行左旋转 + * + * 左旋示意图(对节点x进行左旋): + * px px + * / / + * x y + * / \ --(左旋)-. / \ # + * lx y x ry + * / \ / \ + * ly ry lx ly + * + * + */ + private void leftRotate(RBTNode x) { + // 设置x的右孩子为y + RBTNode y = x.right; + + // 将 “y的左孩子” 设为 “x的右孩子”; + // 如果y的左孩子非空,将 “x” 设为 “y的左孩子的父亲” + x.right = y.left; + if (y.left != null) + y.left.parent = x; + + // 将 “x的父亲” 设为 “y的父亲” + y.parent = x.parent; + + if (x.parent == null) { + this.mRoot = y; // 如果 “x的父亲” 是空节点,则将y设为根节点 + } else { + if (x.parent.left == x) + x.parent.left = y; // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子” + else + x.parent.right = y; // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子” + } + + // 将 “x” 设为 “y的左孩子” + y.left = x; + // 将 “x的父节点” 设为 “y” + x.parent = y; + } + + /** + * 对红黑树的节点(y)进行右旋转 + * + * 右旋示意图(对节点y进行左旋): + * py py + * / / + * y x + * / \ --(右旋)-. / \ # + * x ry lx y + * / \ / \ # + * lx rx rx ry + * + */ + private void rightRotate(RBTNode y) { + // 设置x是当前节点的左孩子。 + RBTNode x = y.left; + + // 将 “x的右孩子” 设为 “y的左孩子”; + // 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲” + y.left = x.right; + if (x.right != null) + x.right.parent = y; + + // 将 “y的父亲” 设为 “x的父亲” + x.parent = y.parent; + + if (y.parent == null) { + this.mRoot = x; // 如果 “y的父亲” 是空节点,则将x设为根节点 + } else { + if (y == y.parent.right) + y.parent.right = x; // 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子” + else + y.parent.left = x; // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子” + } + + // 将 “y” 设为 “x的右孩子” + x.right = y; + + // 将 “y的父节点” 设为 “x” + y.parent = x; + } + + /** + * 红黑树插入修正函数 + * + * 在向红黑树中插入节点之后(失去平衡),再调用该函数; + * 目的是将它重新塑造成一颗红黑树。 + * + * 参数说明: + * node 插入的结点 // 对应《算法导论》中的z + */ + private void insertFixUp(RBTNode node) { + RBTNode parent, gparent; + + // 若“父节点存在,并且父节点的颜色是红色” + while (((parent = parentOf(node))!=null) && isRed(parent)) { + gparent = parentOf(parent); + + //若“父节点”是“祖父节点的左孩子” + if (parent == gparent.left) { + // Case 1条件:叔叔节点是红色 + RBTNode uncle = gparent.right; + if ((uncle!=null) && isRed(uncle)) { + setBlack(uncle); + setBlack(parent); + setRed(gparent); + node = gparent; + continue; + } + + // Case 2条件:叔叔是黑色,且当前节点是右孩子 + if (parent.right == node) { + RBTNode tmp; + leftRotate(parent); + tmp = parent; + parent = node; + node = tmp; + } + + // Case 3条件:叔叔是黑色,且当前节点是左孩子。 + setBlack(parent); + setRed(gparent); + rightRotate(gparent); + } else { //若“z的父节点”是“z的祖父节点的右孩子” + // Case 1条件:叔叔节点是红色 + RBTNode uncle = gparent.left; + if ((uncle!=null) && isRed(uncle)) { + setBlack(uncle); + setBlack(parent); + setRed(gparent); + node = gparent; + continue; + } + + // Case 2条件:叔叔是黑色,且当前节点是左孩子 + if (parent.left == node) { + RBTNode tmp; + rightRotate(parent); + tmp = parent; + parent = node; + node = tmp; + } + + // Case 3条件:叔叔是黑色,且当前节点是右孩子。 + setBlack(parent); + setRed(gparent); + leftRotate(gparent); + } + } + + // 将根节点设为黑色 + setBlack(this.mRoot); + } + + /** + * 将结点插入到红黑树中 + * + * 参数说明: + * node 插入的结点 // 对应《算法导论》中的node + */ + private void insert(RBTNode node) { + int cmp; + RBTNode y = null; + RBTNode x = this.mRoot; + + // 1. 将红黑树当作一颗二叉查找树,将节点添加到二叉查找树中。 + while (x != null) { + y = x; + cmp = node.key.compareTo(x.key); + if (cmp < 0) + x = x.left; + else + x = x.right; + } + + node.parent = y; + if (y!=null) { + cmp = node.key.compareTo(y.key); + if (cmp < 0) + y.left = node; + else + y.right = node; + } else { + this.mRoot = node; + } + + // 2. 设置节点的颜色为红色 + node.color = RED; + + // 3. 将它重新修正为一颗二叉查找树 + insertFixUp(node); + } + + /** + * 新建结点(key),并将其插入到红黑树中 + * + * 参数说明: + * key 插入结点的键值 + */ + public void insert(T key) { + RBTNode node=new RBTNode(key,BLACK,null,null,null); + + // 如果新建结点失败,则返回。 + if (node != null) + insert(node); + } + + + /** + * 红黑树删除修正函数 + * + * 在从红黑树中删除插入节点之后(红黑树失去平衡),再调用该函数; + * 目的是将它重新塑造成一颗红黑树。 + * + * 参数说明: + * node 待修正的节点 + */ + private void removeFixUp(RBTNode node, RBTNode parent) { + RBTNode other; + + while ((node==null || isBlack(node)) && (node != this.mRoot)) { + if (parent.left == node) { + other = parent.right; + if (isRed(other)) { + // Case 1: x的兄弟w是红色的 + setBlack(other); + setRed(parent); + leftRotate(parent); + other = parent.right; + } + + if ((other.left==null || isBlack(other.left)) && + (other.right==null || isBlack(other.right))) { + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + setRed(other); + node = parent; + parent = parentOf(node); + } else { + + if (other.right==null || isBlack(other.right)) { + // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + setBlack(other.left); + setRed(other); + rightRotate(other); + other = parent.right; + } + // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + setColor(other, colorOf(parent)); + setBlack(parent); + setBlack(other.right); + leftRotate(parent); + node = this.mRoot; + break; + } + } else { + + other = parent.left; + if (isRed(other)) { + // Case 1: x的兄弟w是红色的 + setBlack(other); + setRed(parent); + rightRotate(parent); + other = parent.left; + } + + if ((other.left==null || isBlack(other.left)) && + (other.right==null || isBlack(other.right))) { + // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 + setRed(other); + node = parent; + parent = parentOf(node); + } else { + + if (other.left==null || isBlack(other.left)) { + // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 + setBlack(other.right); + setRed(other); + leftRotate(other); + other = parent.left; + } + + // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 + setColor(other, colorOf(parent)); + setBlack(parent); + setBlack(other.left); + rightRotate(parent); + node = this.mRoot; + break; + } + } + } + + if (node!=null) + setBlack(node); + } + + /** + * 删除结点(node),并返回被删除的结点 + * + * 参数说明: + * node 删除的结点 + */ + private void remove(RBTNode node) { + RBTNode child, parent; + boolean color; + + // 被删除节点的"左右孩子都不为空"的情况。 + if ( (node.left!=null) && (node.right!=null) ) { + // 被删节点的后继节点。(称为"取代节点") + // 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。 + RBTNode replace = node; + + // 获取后继节点 + replace = replace.right; + while (replace.left != null) + replace = replace.left; + + // "node节点"不是根节点(只有根节点不存在父节点) + if (parentOf(node)!=null) { + if (parentOf(node).left == node) + parentOf(node).left = replace; + else + parentOf(node).right = replace; + } else { + // "node节点"是根节点,更新根节点。 + this.mRoot = replace; + } + + // child是"取代节点"的右孩子,也是需要"调整的节点"。 + // "取代节点"肯定不存在左孩子!因为它是一个后继节点。 + child = replace.right; + parent = parentOf(replace); + // 保存"取代节点"的颜色 + color = colorOf(replace); + + // "被删除节点"是"它的后继节点的父节点" + if (parent == node) { + parent = replace; + } else { + // child不为空 + if (child!=null) + setParent(child, parent); + parent.left = child; + + replace.right = node.right; + setParent(node.right, replace); + } + + replace.parent = node.parent; + replace.color = node.color; + replace.left = node.left; + node.left.parent = replace; + + if (color == BLACK) + removeFixUp(child, parent); + + node = null; + return ; + } + + if (node.left !=null) { + child = node.left; + } else { + child = node.right; + } + + parent = node.parent; + // 保存"取代节点"的颜色 + color = node.color; + + if (child!=null) + child.parent = parent; + + // "node节点"不是根节点 + if (parent!=null) { + if (parent.left == node) + parent.left = child; + else + parent.right = child; + } else { + this.mRoot = child; + } + + if (color == BLACK) + removeFixUp(child, parent); + node = null; + } + + /** + * 删除结点(z),并返回被删除的结点 + * + * 参数说明: + * tree 红黑树的根结点 + * z 删除的结点 + */ + public void remove(T key) { + RBTNode node; + + if ((node = search(mRoot, key)) != null) + remove(node); + } + + /** + * 销毁红黑树 + */ + private void destroy(RBTNode tree) { + if (tree==null) + return ; + + if (tree.left != null) + destroy(tree.left); + if (tree.right != null) + destroy(tree.right); + + tree=null; + } + + public void clear() { + destroy(mRoot); + mRoot = null; + } + + /** + * 打印"红黑树" + * + * key -- 节点的键值 + * direction -- 0,表示该节点是根节点; + * -1,表示该节点是它的父结点的左孩子; + * 1,表示该节点是它的父结点的右孩子。 + */ + private void print(RBTNode tree, T key, int direction) { + + if(tree != null) { + + if(direction==0) // tree是根节点 + System.out.printf("%2d(B) is root\n", tree.key); + else // tree是分支节点 + System.out.printf("%2d(%s) is %2d's %6s child\n", tree.key, isRed(tree)?"R":"B", key, direction==1?"right" : "left"); + + print(tree.left, tree.key, -1); + print(tree.right,tree.key, 1); + } + } + + public void print() { + if (mRoot != null) + print(mRoot, mRoot.key, 0); + } +} \ No newline at end of file diff --git a/src/main/java/com/lin/tree/nome/rbtree/RBTree2.java b/src/main/java/com/lin/tree/nome/rbtree/RBTree2.java new file mode 100644 index 0000000000000000000000000000000000000000..8c8d7654a5fa779cbf40548bd2b9832712f451e0 --- /dev/null +++ b/src/main/java/com/lin/tree/nome/rbtree/RBTree2.java @@ -0,0 +1,440 @@ +package com.lin.tree.nome.rbtree; + + +public class RBTree2 { + + public static class NodeColor { + public static String Red = "red"; + public static String Black = "black"; + } + + public static class RedBlackTreeNode { + private String color; + private int key; + private RedBlackTreeNode left; + private RedBlackTreeNode right; + private RedBlackTreeNode parent; + + //构造Nil结点 + public RedBlackTreeNode() { + this.color = NodeColor.Black; + this.key = 0; + this.left = null; + this.right = null; + this.parent = null; + } + + //构造结点 + public RedBlackTreeNode(String color, int key, RedBlackTreeNode left, RedBlackTreeNode right, RedBlackTreeNode parent) { + this.color = color; + this.key = key; + this.left = left; + this.right = right; + this.parent = parent; + } + + //获取颜色 + public String getColor() { + return color; + } + + //设置颜色 + public void setColor(String color) { + this.color = color; + } + + //获取值 + public int getKey() { + return key; + } + + //设置值 + public void setKey(int key) { + this.key = key; + } + + //获取左子树 + public RedBlackTreeNode getLeft() { + return left; + } + + //设置左子树 + public void setLeft(RedBlackTreeNode left) { + this.left = left; + } + + //获取右子树 + public RedBlackTreeNode getRight() { + return right; + } + + //设置右子树 + public void setRight(RedBlackTreeNode right) { + this.right = right; + } + + //获取父结点 + public RedBlackTreeNode getParent() { + return parent; + } + + //设置父结点 + public void setParent(RedBlackTreeNode parent) { + this.parent = parent; + } + } + + private static RedBlackTreeNode nil = new RedBlackTreeNode(); + private RedBlackTreeNode root = new RedBlackTreeNode(); + + //构造空红黑树 + public RBTree2() { + root = nil; + } + + //创建结点 + public RedBlackTreeNode RB_NODE(int key) { + RedBlackTreeNode node = new RedBlackTreeNode(NodeColor.Red, key, nil, nil, nil); + return node; + } + + //判断是否为Nil结点 + public boolean IsNil(RedBlackTreeNode node) { + if (node == nil) { + return true; + } else { + return false; + } + } + + //获取根结点 + public RedBlackTreeNode getRoot() { + return root; + } + + //设置根结点 + public void setRoot(RedBlackTreeNode root) { + this.root = root; + } + + //插入结点 + public void RB_INSERT(RBTree2 T, RedBlackTreeNode z) { + //临时变量结点y,存储临时结点,默认为Nil + RedBlackTreeNode y = T.nil; + //x初试为根结点 + RedBlackTreeNode x = T.getRoot(); + //循环二查找合适的插入点 + while (IsNil(x) == false) { + //保存当前结点,作为结果的根结点 + y = x; + if (z.getKey() < x.getKey()) { + //查找左子树 + x = x.getLeft(); + } else { + //查找右子树 + x = x.getRight(); + } + } + //临时结点y设置为插入点的父结点 + z.setParent(y); + + if (IsNil(y) == true) { + //空树时设置z为根结点 + T.setRoot(z); + } else if (z.getKey() < y.getKey()) { + //插入为左子树 + y.setLeft(z); + } else { + //插入为右子树 + y.setRight(z); + } + //将插入结点的左右子树设为Nil,颜色为红色,已经在构造时设置过,可以省略 + z.setLeft(T.nil); + z.setRight(T.nil); + z.setColor(NodeColor.Red); + //插入调整 + RB_INSERT_FIXUP(T, z); + } + + //插入调整 + public void RB_INSERT_FIXUP(RBTree2 T, RedBlackTreeNode z) { + //当z的父结点为红色时,插入结点和父结点同为红色,需要调整 + while (z.getParent().getColor() == NodeColor.Red) { + //插入结点的父结点是祖父节点的左子树 + if (z.getParent() == z.getParent().getParent().getLeft()) { + //y定义为叔叔结点 + RedBlackTreeNode y = z.getParent().getParent().getRight(); + //case1:如果叔叔结点为红色,上层父结点和叔叔结点设为黑色,祖父节点设为红色 + if (y.getColor() == NodeColor.Red) { + z.getParent().setColor(NodeColor.Black); + y.setColor(NodeColor.Black); + z.getParent().getParent().setColor(NodeColor.Red); + //祖父结点设为z + z = z.getParent().getParent(); + } + //case2:插入结点为父结点的右子树,(叔叔结点一定为黑色),父结点设为z,对z左旋 + else if (z == z.getParent().getRight()) { + //对父结点左旋 + z = z.getParent(); + LEFT_ROTATE(T, z); + } + //case3:插入结点为父结点的左子树,(叔叔结点一定为黑色),父结点设为黑色,祖父结点设为红色,对祖父结点右旋 + z.getParent().setColor(NodeColor.Black); + z.getParent().getParent().setColor(NodeColor.Red); + RIGHT_ROTATE(T, z.getParent().getParent()); + } + //插入结点的父结点是祖父节点的右子树,同理,方向交换 + else { + RedBlackTreeNode y = z.getParent().getParent().getLeft(); + if (y.getColor() == NodeColor.Red) { + z.getParent().setColor(NodeColor.Black); + y.setColor(NodeColor.Black); + z.getParent().getParent().setColor(NodeColor.Red); + z = z.getParent().getParent(); + } else if (z == z.getParent().getLeft()) { + z = z.getParent(); + RIGHT_ROTATE(T, z); + } + z.getParent().setColor(NodeColor.Black); + z.getParent().getParent().setColor(NodeColor.Red); + LEFT_ROTATE(T, z.getParent().getParent()); + } + } + T.getRoot().setColor(NodeColor.Black); + } + + //删除结点子函数,把根结点为u的子树替换为根结点为v的子树 + public void RB_TRANSPLANT(RBTree2 T, RedBlackTreeNode u, RedBlackTreeNode v) { + //u为根结点 + if (IsNil(u.getParent())) { + T.root = v; + } + //u为左子树 + else if (u == u.getParent().getLeft()) { + u.getParent().setLeft(v); + } + //u为右子树 + else { + u.getParent().setRight(v); + } + //父结点交换 + v.setParent(u.getParent()); + } + + //查找后继 + public RedBlackTreeNode TREE_MINIMUM(RedBlackTreeNode x) { + //不断查找左子树 + while (IsNil(x.getLeft()) == false) { + x = x.getLeft(); + } + return x; + } + + //删除结点 + public void RB_DELETE(RBTree2 T, RedBlackTreeNode z) { + //临时结点y保存即将删除的结点z信息 + RedBlackTreeNode y = z; + //在结点删除或者移动前必须保存结点的颜色 + String yOriginColor = y.getColor(); + //临时结点x,用于记录y的位置 + RedBlackTreeNode x = null; + //case1:z无左子树,直接将右子树置于z位置 + if (IsNil(z.getLeft()) == true) { + x = z.getRight(); + RB_TRANSPLANT(T, z, z.getRight()); + } + //case2:z无右子树,直接将左子树置于z位置 + else if (IsNil(z.getRight()) == true) { + x = z.getLeft(); + RB_TRANSPLANT(T, z, z.getLeft()); + } + //case3:z有左右子树 + else { + //找到右子树中最小的结点,即z的后继 + y = TREE_MINIMUM(z.getRight()); + //删除的实际是y的位置的结点,要记录y的颜色 + yOriginColor = y.getColor(); + //y可能有右孩子,一定无左孩子,保存右孩子 + x = y.getRight(); + //若y为z的右孩子,直接相连 + if (y.getParent() == z) { + x.setParent(y); + } + //若不相连 + else { + RB_TRANSPLANT(T, y, y.getRight()); + y.setRight(z.getRight()); + y.getRight().setParent(y); + } + RB_TRANSPLANT(T, z, y); + y.setLeft(z.getLeft()); + y.getLeft().setParent(y); + y.setColor(z.getColor()); + } + //删除结点为黑色时需要调整 + if (yOriginColor == NodeColor.Black) { + RB_DELETE_FIXUP(T, x); + } + } + + //删除调整 + public void RB_DELETE_FIXUP(RBTree2 T, RedBlackTreeNode x) { + //临时结点 + RedBlackTreeNode w = null; + //非根结点且为黑色 + while (x != T.getRoot() && x.getColor() == NodeColor.Black) { + //x为父结点左孩子 + if (x == x.getParent().getLeft()) { + //w为兄弟结点 + w = x.getParent().getRight(); + //case1:w兄弟结点为红色 + if (w.getColor() == NodeColor.Red) { + //w设为黑色 + w.setColor(NodeColor.Black); + //被删结点的父结点设为黑色 + x.getParent().setColor(NodeColor.Red); + //对x的父结点左旋 + LEFT_ROTATE(T, x.getParent()); + //更新x的兄弟结点 + w = x.getParent().getRight(); + } + //case2:w兄弟结点和两个孩子结点都为黑 + if (w.getLeft().getColor() == NodeColor.Black && w.getRight().getColor() == NodeColor.Black) { + //w设为黑色 + w.setColor(NodeColor.Red); + //重设x为x的父结点 + x = x.getParent(); + } + //case3:w兄弟结点为黑,w的左孩子为红,右孩子为黑 + else if (w.getRight().getColor() == NodeColor.Black) { + //w的左孩子设为黑 + w.getLeft().setColor(NodeColor.Black); + //w设为红 + w.setColor(NodeColor.Red); + //右旋 + RIGHT_ROTATE(T, w); + //更新w + w = x.getParent().getRight(); + } + //case4:w兄弟结点为黑,w的右孩子为红 + w.setColor(x.getParent().getColor()); + x.getParent().setColor(NodeColor.Black); + w.getRight().setColor(NodeColor.Black); + LEFT_ROTATE(T, x.getParent()); + x = T.getRoot(); + } + //x为父结点右孩子 + else { + w = x.getParent().getLeft(); + if (w.getColor() == NodeColor.Red) { + w.setColor(NodeColor.Black); + x.getParent().setColor(NodeColor.Red); + RIGHT_ROTATE(T, x.getParent()); + w = x.getParent().getLeft(); + } + if (w.getRight().getColor() == NodeColor.Black && w.getLeft().getColor() == NodeColor.Black) { + w.setColor(NodeColor.Red); + x = x.getParent(); + } else if (w.getLeft().getColor() == NodeColor.Black) { + w.getRight().setColor(NodeColor.Black); + w.setColor(NodeColor.Red); + LEFT_ROTATE(T, w); + w = x.getParent().getLeft(); + } + w.setColor(x.getParent().getColor()); + x.getParent().setColor(NodeColor.Black); + w.getLeft().setColor(NodeColor.Black); + RIGHT_ROTATE(T, x.getParent()); + x = T.getRoot(); + } + } + x.setColor(NodeColor.Black); + } + + //左旋 + public void LEFT_ROTATE(RBTree2 T, RedBlackTreeNode x) { + //左旋结点右子树不能为空 + if (IsNil(x.getRight()) == true) + return; + //定义y结点 + RedBlackTreeNode y = x.getRight(); + //y左子树 -> x右子树 + x.setRight(y.getLeft()); + //x -> y左子树父结点 + y.getLeft().setParent(x); + //x父结点 -> y父结点 + y.setParent(x.getParent()); + //y -> x父结点左/右子树或根结点 + if (IsNil(x.getParent()) == true) { + //x为根结点,y设为根结点 + T.setRoot(y); + } else if (x.getParent().getLeft() == x) { + //x为左子树,y设为左子树 + x.getParent().setLeft(y); + } else { + //x为右子树,y设为右子树 + x.getParent().setRight(y); + } + //x -> y左子树 + y.setLeft(x); + //y -> x父结点 + x.setParent(y); + } + + //右旋 + public void RIGHT_ROTATE(RBTree2 T, RedBlackTreeNode x) { + //右旋结点父结点不能为空 + if (IsNil(x.getParent()) == true) + return; + //定义y结点 + RedBlackTreeNode y = x.getParent(); + //x右子树 -> y左子树 + y.setLeft(x.getRight()); + //y -> x右子树父结点 + x.getRight().setParent(y); + //y父结点 -> x父结点 + x.setParent(y.getParent()); + //x -> y父结点左/右子树或根结点 + if (IsNil(y.getParent()) == true) { + //y为根结点,x设为根结点 + T.setRoot(x); + } else if (y.getParent().getLeft() == y) { + //y为左子树,x设为左子树 + y.getParent().setLeft(x); + } else { + //y为右子树,x设为右子树 + y.getParent().setRight(x); + } + //y -> x右子树 + x.setRight(y); + //x -> y父结点 + y.setParent(x); + } + + //前序遍历 + public void preorder(RedBlackTreeNode t) { + if (IsNil(t) == false) { + System.out.println(t.getKey()); + preorder(t.getLeft()); + preorder(t.getRight()); + } + } + + //中序遍历 + public void midorder(RedBlackTreeNode t) { + if (IsNil(t) == false) { + midorder(t.getLeft()); + System.out.println(t.getKey()); + midorder(t.getRight()); + } + } + + //后序遍历 + public void postorder(RedBlackTreeNode t) { + if (IsNil(t) == false) { + postorder(t.getLeft()); + postorder(t.getRight()); + System.out.println(t.getKey()); + } + } +} diff --git a/src/main/java/com/lin/Util/ExcelExportUtil.java b/src/main/java/com/lin/util/ExcelExportUtil.java similarity index 99% rename from src/main/java/com/lin/Util/ExcelExportUtil.java rename to src/main/java/com/lin/util/ExcelExportUtil.java index 9a2957af339d0d718235a8c03dfc08cfa47daaf3..bd263362ec830e9db53df4390e4c45c5868ed1c8 100644 --- a/src/main/java/com/lin/Util/ExcelExportUtil.java +++ b/src/main/java/com/lin/util/ExcelExportUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/lin/Util/ExcelImportUtil.java b/src/main/java/com/lin/util/ExcelImportUtil.java similarity index 99% rename from src/main/java/com/lin/Util/ExcelImportUtil.java rename to src/main/java/com/lin/util/ExcelImportUtil.java index f423a8dff4449ad619eb1b1317fd2f0dac545a9a..c9da58c2f5edbfb07272c08da9dbcd99048b71e7 100644 --- a/src/main/java/com/lin/Util/ExcelImportUtil.java +++ b/src/main/java/com/lin/util/ExcelImportUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/lin/Util/FileReadUtil.java b/src/main/java/com/lin/util/FileReadUtil.java similarity index 98% rename from src/main/java/com/lin/Util/FileReadUtil.java rename to src/main/java/com/lin/util/FileReadUtil.java index ba5c2372a4158479dc7bc65253de54d75f9fa36b..2e33e8fa863ae40239efb8b5e48fb1b60c4d88ab 100644 --- a/src/main/java/com/lin/Util/FileReadUtil.java +++ b/src/main/java/com/lin/util/FileReadUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/com/lin/Util/FileWriteUtil.java b/src/main/java/com/lin/util/FileWriteUtil.java similarity index 99% rename from src/main/java/com/lin/Util/FileWriteUtil.java rename to src/main/java/com/lin/util/FileWriteUtil.java index b3cbe26f63e5333e16a82accbe5bff524a8c93d2..ca6a7051711d5126545299eccf78e11c28c98a86 100644 --- a/src/main/java/com/lin/Util/FileWriteUtil.java +++ b/src/main/java/com/lin/util/FileWriteUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/lin/Util/HttpConnectionUtil.java b/src/main/java/com/lin/util/HttpConnectionUtil.java similarity index 99% rename from src/main/java/com/lin/Util/HttpConnectionUtil.java rename to src/main/java/com/lin/util/HttpConnectionUtil.java index ee82de7c00f8ca344657f63eb40b7a50cc463f04..911d3cc58eac6eff83eee4995d8df13704134026 100644 --- a/src/main/java/com/lin/Util/HttpConnectionUtil.java +++ b/src/main/java/com/lin/util/HttpConnectionUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; diff --git a/src/main/java/com/lin/Util/HttpUrlConnectionUtil.java b/src/main/java/com/lin/util/HttpUrlConnectionUtil.java similarity index 99% rename from src/main/java/com/lin/Util/HttpUrlConnectionUtil.java rename to src/main/java/com/lin/util/HttpUrlConnectionUtil.java index b9406d956e7df23cb69d7b9fddac131aba4d1b67..520aa756a195198e197ea38ecbf5c8dff2f53cf8 100644 --- a/src/main/java/com/lin/Util/HttpUrlConnectionUtil.java +++ b/src/main/java/com/lin/util/HttpUrlConnectionUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.IOUtils; diff --git a/src/main/java/com/lin/Util/InvokeUtil.java b/src/main/java/com/lin/util/InvokeUtil.java similarity index 96% rename from src/main/java/com/lin/Util/InvokeUtil.java rename to src/main/java/com/lin/util/InvokeUtil.java index fd309e8361f44ff3c98b0a5aa559c35d58b99f76..ec34cd5f9b98a6debe73fb3779d14b69c0d1333b 100644 --- a/src/main/java/com/lin/Util/InvokeUtil.java +++ b/src/main/java/com/lin/util/InvokeUtil.java @@ -1,11 +1,8 @@ -package com.lin.Util; +package com.lin.util; -import com.sun.org.apache.xpath.internal.operations.Bool; import lombok.extern.slf4j.Slf4j; -import javax.swing.*; import java.lang.reflect.Field; -import java.lang.reflect.Type; import java.util.Map; /** diff --git a/src/main/java/com/lin/Util/XmlParseUtil.java b/src/main/java/com/lin/util/XmlParseUtil.java similarity index 99% rename from src/main/java/com/lin/Util/XmlParseUtil.java rename to src/main/java/com/lin/util/XmlParseUtil.java index 0456574272be25048d885e71a36033e1ff2334fc..0d132879c998a0934bb01b039562edc7f4926a63 100644 --- a/src/main/java/com/lin/Util/XmlParseUtil.java +++ b/src/main/java/com/lin/util/XmlParseUtil.java @@ -1,4 +1,4 @@ -package com.lin.Util; +package com.lin.util; import lombok.extern.slf4j.Slf4j; import org.w3c.dom.Document; diff --git a/src/test/java/com/lin/TestSort/BubbleSortTest.java b/src/test/java/com/lin/TestSort/BubbleSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ba6176f0da3f7449d5531ba76747c6355da17226 --- /dev/null +++ b/src/test/java/com/lin/TestSort/BubbleSortTest.java @@ -0,0 +1,20 @@ +package com.lin.TestSort; + +import com.lin.enums.StatusCode; +import com.lin.sort.BubbleSort; +import org.junit.Test; + +public class BubbleSortTest { + + + @Test + public void bubbleSortedTest(){ + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + BubbleSort.bubbleSorted(a, StatusCode.MAX_SORT); + for (int i : a) { + System.out.println(i); + } + + } + +} diff --git a/src/test/java/com/lin/TestSort/BucketSortTest.java b/src/test/java/com/lin/TestSort/BucketSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..41abc9e1425964ea5f1c7b99d75c2fd257209d73 --- /dev/null +++ b/src/test/java/com/lin/TestSort/BucketSortTest.java @@ -0,0 +1,17 @@ +package com.lin.TestSort; + +import com.lin.sort.BucketSort; +import org.junit.Test; + +public class BucketSortTest { + + + @Test + public void bucketSortedTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + int[] countingsorted = BucketSort.bucketSorted(a); + for (int i : countingsorted) { + System.out.println(i); + } + } +} diff --git a/src/test/java/com/lin/TestSort/CountingSortTest.java b/src/test/java/com/lin/TestSort/CountingSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..ee183b38b2895c3e74841f8993e3fba3a7ae5a3d --- /dev/null +++ b/src/test/java/com/lin/TestSort/CountingSortTest.java @@ -0,0 +1,17 @@ +package com.lin.TestSort; + +import com.lin.sort.CountingSort; +import org.junit.Test; + +public class CountingSortTest { + + + @Test + public void countingSortedTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + int[] countingsorted = CountingSort.countingsorted(a); + for (int i : countingsorted) { + System.out.println(i); + } + } +} diff --git a/src/test/java/com/lin/TestSort/HeapSortTest.java b/src/test/java/com/lin/TestSort/HeapSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fe9a2fed853ad1b3cb41cc4c1ebdab195a05a9d6 --- /dev/null +++ b/src/test/java/com/lin/TestSort/HeapSortTest.java @@ -0,0 +1,19 @@ +package com.lin.TestSort; + +import com.lin.enums.StatusCode; +import com.lin.sort.HeapSort; +import org.junit.Test; + +public class HeapSortTest { + + + @Test + public void heapSrotTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + HeapSort.heapSorted(a, StatusCode.MAX_SORT); + for (int i : a) { + System.out.println(i); + } + } + +} diff --git a/src/test/java/com/lin/TestSort/InsertionSortTest.java b/src/test/java/com/lin/TestSort/InsertionSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..267f3245993ae7a38f1c54903b2818540bb2aaac --- /dev/null +++ b/src/test/java/com/lin/TestSort/InsertionSortTest.java @@ -0,0 +1,29 @@ +package com.lin.TestSort; + +import com.lin.enums.StatusCode; +import com.lin.sort.InsertionSort; +import org.junit.Test; + +public class InsertionSortTest { + + + @Test + public void insertionSortedtest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + InsertionSort.insertionSorted(a, StatusCode.MIX_SORT); + for (int i : a) { + System.out.println(i); + } + } + + @Test + public void insertionSortedDichotomyTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + InsertionSort.insertionSortedDichotomy(a, StatusCode.MIX_SORT); + for (int i : a) { + System.out.println(i); + } + } + + +} diff --git a/src/test/java/com/lin/TestSort/MergeSortTest.java b/src/test/java/com/lin/TestSort/MergeSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..8e8897788a3ab91cf6ffc74e0a7842e49a35d4ed --- /dev/null +++ b/src/test/java/com/lin/TestSort/MergeSortTest.java @@ -0,0 +1,28 @@ +package com.lin.TestSort; + +import com.lin.enums.StatusCode; +import com.lin.sort.MergeSort; +import org.junit.Test; + +public class MergeSortTest { + + + @Test + public void mergeSortedRecursionTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + MergeSort.mergeSortedRecursion(a, StatusCode.MAX_SORT, 0, a.length - 1); + for (int i : a) { + System.out.println(i); + } + } + + @Test + public void mergeSortedIterationTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + MergeSort.mergeSortedIteration(a, StatusCode.MIX_SORT); + for (int i : a) { + System.out.println(i); + } + } + +} diff --git a/src/test/java/com/lin/TestSort/QuickSortedTest.java b/src/test/java/com/lin/TestSort/QuickSortedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2127f637043cef909152f7639ceb5e9e89a338de --- /dev/null +++ b/src/test/java/com/lin/TestSort/QuickSortedTest.java @@ -0,0 +1,19 @@ +package com.lin.TestSort; + +import com.lin.enums.StatusCode; +import com.lin.sort.QuickSort; +import org.junit.Test; + +public class QuickSortedTest { + + + @Test + public void quickSortedTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + QuickSort.quickSorted(a, 0, a.length - 1, StatusCode.MAX_SORT); + for (int i : a) { + System.out.println(i); + } + } + +} diff --git a/src/test/java/com/lin/TestSort/RadixSortTest.java b/src/test/java/com/lin/TestSort/RadixSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bc424bdbca609481f485f23e6714b55223daf917 --- /dev/null +++ b/src/test/java/com/lin/TestSort/RadixSortTest.java @@ -0,0 +1,20 @@ +package com.lin.TestSort; + +import com.lin.sort.RadixSort; +import org.junit.Test; + +public class RadixSortTest { + + + @Test + public void radixSortedTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + int[] countingsorted = RadixSort.radixSorted(a); + for (int i : countingsorted) { + System.out.println(i); + } + } + + + +} diff --git a/src/test/java/com/lin/TestSort/SelectionSortTest.java b/src/test/java/com/lin/TestSort/SelectionSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3981aa6331e3cab68f4b2a472aa5f418eb44ed3c --- /dev/null +++ b/src/test/java/com/lin/TestSort/SelectionSortTest.java @@ -0,0 +1,18 @@ +package com.lin.TestSort; + +import com.lin.enums.StatusCode; +import com.lin.sort.SelectionSort; +import org.junit.Test; + +public class SelectionSortTest { + + + @Test + public void selectionSortedTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + SelectionSort.selectionSorted(a, StatusCode.MIX_SORT); + for (int i : a) { + System.out.println(i); + } + } +} diff --git a/src/test/java/com/lin/TestSort/ShellSortTest.java b/src/test/java/com/lin/TestSort/ShellSortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..86807ae0666ac9e8760264300b0cd6e42b4f6b17 --- /dev/null +++ b/src/test/java/com/lin/TestSort/ShellSortTest.java @@ -0,0 +1,19 @@ +package com.lin.TestSort; + +import com.lin.enums.StatusCode; +import com.lin.sort.ShellSort; +import org.junit.Test; + +public class ShellSortTest { + + @Test + public void shellSortTest() { + int[] a = {1, 6, 8, 2, 4, 5, 7, 1, 0}; + ShellSort.shellSorted(a, StatusCode.MIX_SORT); + for (int i : a) { + System.out.println(i); + } + } + + +} diff --git a/src/test/java/com/lin/TestSort/v3.0.md b/src/test/java/com/lin/TestSort/v3.0.md new file mode 100644 index 0000000000000000000000000000000000000000..4305f784f548b7a44cb2735377ad06610c5087c2 --- /dev/null +++ b/src/test/java/com/lin/TestSort/v3.0.md @@ -0,0 +1,9 @@ +# V3.0 + +1. 冒泡排序工具 +2. 选择排序 +3. 插入排序 +4. 选择排序 +5. 归并排序 +6. 希尔排序 +7. 堆排序 \ No newline at end of file diff --git a/src/test/java/com/lin/TestTree/AVLTree1Test.java b/src/test/java/com/lin/TestTree/AVLTree1Test.java new file mode 100644 index 0000000000000000000000000000000000000000..09bd06cffcd5da44d0156543af935487a4aa8611 --- /dev/null +++ b/src/test/java/com/lin/TestTree/AVLTree1Test.java @@ -0,0 +1,28 @@ +package com.lin.TestTree; + +import com.lin.tree.nome.avltree.AVLTree1; + +public class AVLTree1Test { + + public static void main(String[] args) { + AVLTree1 avl = new AVLTree1<>(); + /*可自行添加插入,删除操作进行测试*/ + avl.insert(3); + avl.insert(5); + avl.insert(6); + avl.insert(7); + avl.insert(8); + avl.insert(9); + avl.preorderTraverse(); + System.out.println(); + System.out.println(avl.size()); + + avl.delete(7); + avl.delete(8); + avl.preorderTraverse(); + System.out.println(); + System.out.println(avl.size()); + } + + +} diff --git a/src/test/java/com/lin/TestTree/RBTree2Test.java b/src/test/java/com/lin/TestTree/RBTree2Test.java new file mode 100644 index 0000000000000000000000000000000000000000..ffbd302675a67cfae9f4e8a60908fef67eb1279f --- /dev/null +++ b/src/test/java/com/lin/TestTree/RBTree2Test.java @@ -0,0 +1,22 @@ +package com.lin.TestTree; + +import com.lin.tree.nome.rbtree.RBTree2; + + +public class RBTree2Test { + + + public static void main(String[] args) { + RBTree2 T = new RBTree2(); + RBTree2.RedBlackTreeNode node1 = T.RB_NODE(10); + T.RB_INSERT(T, node1); + RBTree2.RedBlackTreeNode node2 = T.RB_NODE(20); + T.RB_INSERT(T, node2); + RBTree2.RedBlackTreeNode node3 = T.RB_NODE(30); + T.RB_INSERT(T, node3); + T.preorder(T.getRoot()); + } + + + +} diff --git a/src/test/java/com/lin/TestTree/v4.0.md b/src/test/java/com/lin/TestTree/v4.0.md new file mode 100644 index 0000000000000000000000000000000000000000..f3f3f470c0ca785279eae09cdf3e214a92d6d1be --- /dev/null +++ b/src/test/java/com/lin/TestTree/v4.0.md @@ -0,0 +1,8 @@ +# V4.0 + +1. AVL树实现算法1 +2. AVL树实现算法2 +3. 红黑树实现算法1 +4. 红黑树实现算法2 +5. 二叉平衡树实现算法 +6. 普通二叉树6 \ No newline at end of file diff --git a/src/test/java/com/lin/TestUtil/ExcelTest.java b/src/test/java/com/lin/TestUtil/ExcelTest.java index 316469f66701b02075f3af87032c82b927dd184b..f13923a2dfc648a9dbe97550b044f66fc515ba48 100644 --- a/src/test/java/com/lin/TestUtil/ExcelTest.java +++ b/src/test/java/com/lin/TestUtil/ExcelTest.java @@ -1,9 +1,9 @@ package com.lin.TestUtil; import com.lin.Dto.BookDto; -import com.lin.Util.ExcelExportUtil; -import com.lin.Util.ExcelImportUtil; -import com.lin.Util.FileWriteUtil; +import com.lin.util.ExcelExportUtil; +import com.lin.util.ExcelImportUtil; +import com.lin.util.FileWriteUtil; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.junit.Test; diff --git a/src/test/java/com/lin/TestUtil/FileTest.java b/src/test/java/com/lin/TestUtil/FileTest.java index 505ace7943b2ba6da2ba4f1faebb6fa13da09952..a24d1cb7a0f4c73f624559d7b10ec788c7cdd75a 100644 --- a/src/test/java/com/lin/TestUtil/FileTest.java +++ b/src/test/java/com/lin/TestUtil/FileTest.java @@ -2,8 +2,8 @@ package com.lin.TestUtil; import com.alibaba.fastjson.JSON; import com.lin.Dto.SenseCallbackDto; -import com.lin.Util.FileReadUtil; -import com.lin.Util.FileWriteUtil; +import com.lin.util.FileReadUtil; +import com.lin.util.FileWriteUtil; import org.junit.Test; import java.io.IOException; diff --git a/src/test/java/com/lin/TestUtil/HttpConnectionTest.java b/src/test/java/com/lin/TestUtil/HttpConnectionTest.java index e1eb40915da890a740003dfcf36dd6e27bccb880..4e2651460803af7dc23a7753a88c2149b16d84ed 100644 --- a/src/test/java/com/lin/TestUtil/HttpConnectionTest.java +++ b/src/test/java/com/lin/TestUtil/HttpConnectionTest.java @@ -1,7 +1,7 @@ package com.lin.TestUtil; -import com.lin.Util.HttpConnectionUtil; -import com.lin.Util.HttpUrlConnectionUtil; +import com.lin.util.HttpConnectionUtil; +import com.lin.util.HttpUrlConnectionUtil; import org.junit.Test; /** diff --git a/src/test/java/com/lin/TestUtil/InvokeTest.java b/src/test/java/com/lin/TestUtil/InvokeTest.java index 56eb3f48f7f469ba85a32e691765b4a625ff9e79..17438fffa602b2b0d721414f3e1fe9f676d004e7 100644 --- a/src/test/java/com/lin/TestUtil/InvokeTest.java +++ b/src/test/java/com/lin/TestUtil/InvokeTest.java @@ -3,8 +3,8 @@ package com.lin.TestUtil; import com.lin.Dto.BookDto; import com.lin.Dto.SenseCallbackDto; import com.lin.Dto.TestDto; -import com.lin.Util.InvokeUtil; -import com.lin.Util.XmlParseUtil; +import com.lin.util.InvokeUtil; +import com.lin.util.XmlParseUtil; import org.junit.Test; import org.w3c.dom.Node; import org.w3c.dom.NodeList; diff --git a/src/test/java/com/lin/TestUtil/XmlTest.java b/src/test/java/com/lin/TestUtil/XmlTest.java index e962f2246fdc4ab344e487930c9781bf58df56e4..92282561206022efc0b2f0f673cb838e63255177 100644 --- a/src/test/java/com/lin/TestUtil/XmlTest.java +++ b/src/test/java/com/lin/TestUtil/XmlTest.java @@ -1,16 +1,11 @@ package com.lin.TestUtil; -import com.lin.Util.FileReadUtil; -import com.lin.Util.XmlParseUtil; +import com.lin.util.XmlParseUtil; import org.junit.Test; import org.xml.sax.SAXException; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; -import java.io.InputStream; -import java.net.URL; /** * Xml相关测试工具