当前位置: 首页 > article >正文

有序表常见题型

给定一个数组arr和两个整数a和b求arr中有多少个子数组累加和在a到b这个范围上返回达标的子数组数量

如【3,6,1,9,2】达标的子数组通过暴力求解的方式时间复杂度为O(N的三次方)【找每个子数组占用O(N的二次方)的时间复杂度,然后再算每个子数组的和占用O(N)的时间复杂度总的占用了O(N的三次方的时间复杂度)】
用前缀和的思想可以将时间复杂度降低到O(N的二次方的时间复杂度)

这个题有一个O(N*logN的解法)
分析:假设现在来到i位置,子数组必须以i位置的数结尾达标的有多少个,依次计算,最后求和则得到最终的结果。
假设要求必须以17结尾的子数组范围在[10,60]的有多少个,
假设现在0-17的前缀和是100,假设0-5的前缀和是5,那么可以推出6-17的累加和为95。
那么只要能够找到任何一个前缀和落在[40,90]的范围,那么就能得到以17结尾的子数组落在[10,60]范围。
做法:
有如下数组:
[3,-2,4,3,6,-1] 范围是[1,5]的,假设有一个结构,这个结构是接收前缀和的,那么对于遍历到的当前数x,则需要判断当前数x是否在[1,5]的范围上,以及它的前缀和是否存在落在[sum(x)-5,sum(x)-1]范围上。
那么对于如上数组:
第一步:首先是一个数也没有的时候,我的前缀和结构提前放入一个0,我要整体以0位置结尾落在1-5的范围上,我就在结构中查有多少个前缀和落在[-2,2]上,发现有一个,然后我再将自己的前缀和3扔进前缀和结构
在这里插入图片描述
第二步:来到1位置,整体前缀和是1,那么则需要找到在这个前缀和结构中范围落在[-4,0]上面,发现有1个,然后我再将1位置的前缀和加入
在这里插入图片描述
第三步:来到2位置,前缀和为5,那么需要找到有多少前缀和范围落在[0,4]范围上,发现有三个,再将5加入结构中。
依次类推下去得到最终的结果。

如何实现这个前缀和结构:
结构的特点:
1、这个结构能往里加整数
2、能够接收一个数字范围并且能够返回满足数字范围上的数有多少个
3、这个结构能接收重复的数字(我多个范围可能有相同的前缀和)
那么我可以做一个小于某个key值的接口把范围内的数给拼接出来。
问题:
有序表是不能有重复数字,解决方案:
我们可以将重复数字压在一起从而实现解决。

public class CountofRangeSum {

	public static int countRangeSum1(int[] nums, int lower, int upper) {
		int n = nums.length;
		long[] sums = new long[n + 1];
		for (int i = 0; i < n; ++i)
			sums[i + 1] = sums[i] + nums[i];
		return countWhileMergeSort(sums, 0, n + 1, lower, upper);
	}

	private static int countWhileMergeSort(long[] sums, int start, int end, int lower, int upper) {
		if (end - start <= 1)
			return 0;
		int mid = (start + end) / 2;
		int count = countWhileMergeSort(sums, start, mid, lower, upper)
				+ countWhileMergeSort(sums, mid, end, lower, upper);
		int j = mid, k = mid, t = mid;
		long[] cache = new long[end - start];
		for (int i = start, r = 0; i < mid; ++i, ++r) {
			while (k < end && sums[k] - sums[i] < lower)
				k++;
			while (j < end && sums[j] - sums[i] <= upper)
				j++;
			while (t < end && sums[t] < sums[i])
				cache[r++] = sums[t++];
			cache[r] = sums[i];
			count += j - k;
		}
		System.arraycopy(cache, 0, sums, start, t - start);
		return count;
	}

	public static class SBTNode {
		//参与排序的key
		public long key;
		//左孩子右孩子
		public SBTNode l;
		public SBTNode r;
		//平衡因子
		public long size; // 不同key的size
		//附加的数据项
		public long all; // 总的size

		public SBTNode(long k) {
			key = k;
			size = 1;
			all = 1;
		}
	}

	public static class SizeBalancedTreeSet {
		private SBTNode root;
		private HashSet<Long> set = new HashSet<>();

		private SBTNode rightRotate(SBTNode cur) {
			long same = cur.all - (cur.l != null ? cur.l.all : 0) - (cur.r != null ? cur.r.all : 0);
			SBTNode leftNode = cur.l;
			cur.l = leftNode.r;
			leftNode.r = cur;
			leftNode.size = cur.size;
			cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
			// all modify
			leftNode.all = cur.all;
			cur.all = (cur.l != null ? cur.l.all : 0) + (cur.r != null ? cur.r.all : 0) + same;
			return leftNode;
		}

		private SBTNode leftRotate(SBTNode cur) {
			long same = cur.all - (cur.l != null ? cur.l.all : 0) - (cur.r != null ? cur.r.all : 0);
			SBTNode rightNode = cur.r;
			cur.r = rightNode.l;
			rightNode.l = cur;
			rightNode.size = cur.size;
			cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
			// all modify
			rightNode.all = cur.all;
			cur.all = (cur.l != null ? cur.l.all : 0) + (cur.r != null ? cur.r.all : 0) + same;
			return rightNode;
		}

		private SBTNode maintain(SBTNode cur) {
			if (cur == null) {
				return null;
			}
			long leftSize = cur.l != null ? cur.l.size : 0;
			long leftLeftSize = cur.l != null && cur.l.l != null ? cur.l.l.size : 0;
			long leftRightSize = cur.l != null && cur.l.r != null ? cur.l.r.size : 0;
			long rightSize = cur.r != null ? cur.r.size : 0;
			long rightLeftSize = cur.r != null && cur.r.l != null ? cur.r.l.size : 0;
			long rightRightSize = cur.r != null && cur.r.r != null ? cur.r.r.size : 0;
			if (leftLeftSize > rightSize) {
				cur = rightRotate(cur);
				cur.r = maintain(cur.r);
				cur = maintain(cur);
			} else if (leftRightSize > rightSize) {
				cur.l = leftRotate(cur.l);
				cur = rightRotate(cur);
				cur.l = maintain(cur.l);
				cur.r = maintain(cur.r);
				cur = maintain(cur);
			} else if (rightRightSize > leftSize) {
				cur = leftRotate(cur);
				cur.l = maintain(cur.l);
				cur = maintain(cur);
			} else if (rightLeftSize > leftSize) {
				cur.r = rightRotate(cur.r);
				cur = leftRotate(cur);
				cur.l = maintain(cur.l);
				cur.r = maintain(cur.r);
				cur = maintain(cur);
			}
			return cur;
		}

		private SBTNode add(SBTNode cur, long key, boolean contains) {
			if (cur == null) {
				return new SBTNode(key);
			} else {
				cur.all++;
				if (key == cur.key) {
					return cur;
				} else { // 还在左滑或者右滑
					if (!contains) {
						cur.size++;
					}
					if (key < cur.key) {
						cur.l = add(cur.l, key, contains);
					} else {
						cur.r = add(cur.r, key, contains);
					}
					return maintain(cur);
				}
			}
		}

		public void add(long sum) {
			boolean contains = set.contains(sum);
			root = add(root, sum, contains);
			set.add(sum);
		}

		public long lessKeySize(long key) {
			SBTNode cur = root;
			long ans = 0;
			while (cur != null) {
				if (key == cur.key) {
					//左树不为空则加上左树的all
					return ans + (cur.l != null ? cur.l.all : 0);
				} else if (key < cur.key) {
					cur = cur.l;
				} else {
					ans += cur.all - (cur.r != null ? cur.r.all : 0);
					cur = cur.r;
				}
			}
			return ans;
		}

		// > 7 8...
		// <8 ...<=7
		public long moreKeySize(long key) {
			return root != null ? (root.all - lessKeySize(key + 1)) : 0;
		}

	}

	public static int countRangeSum2(int[] nums, int lower, int upper) {
		// 黑盒,加入数字(前缀和),不去重,可以接受重复数字
		//支持查询 < num , 有几个数?
		SizeBalancedTreeSet treeSet = new SizeBalancedTreeSet();
		long sum = 0;
		int ans = 0;
		treeSet.add(0);// 一个数都没有的时候,就已经有一个前缀和累加和为0,
		for (int i = 0; i < nums.length; i++) {
			sum += nums[i];
			//之前有多少个前缀和落在[sum - upper, sum - lower]
			// [10, 20] ? 如果要查落在10到20范围上的数有多少个
			// 那么需要查< 10 的有多少个  < 21 的有多少个
			long a = treeSet.lessKeySize(sum - lower + 1);
			long b = treeSet.lessKeySize(sum - upper);
			//加上结果
			ans += a - b;
			//放入当前前缀和
			treeSet.add(sum);
		}
		return ans;
	}

	// for test
	public static void printArray(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}

	// for test
	public static int[] generateArray(int len, int varible) {
		int[] arr = new int[len];
		for (int i = 0; i < arr.length; i++) {
			arr[i] = (int) (Math.random() * varible);
		}
		return arr;
	}

	public static void main(String[] args) {
		int len = 200;
		int varible = 50;
		for (int i = 0; i < 10000; i++) {
			int[] test = generateArray(len, varible);
			int lower = (int) (Math.random() * varible) - (int) (Math.random() * varible);
			int upper = lower + (int) (Math.random() * varible);
			int ans1 = countRangeSum1(test, lower, upper);
			int ans2 = countRangeSum2(test, lower, upper);
			if (ans1 != ans2) {
				printArray(test);
				System.out.println(lower);
				System.out.println(upper);
				System.out.println(ans1);
				System.out.println(ans2);
			}
		}

	}

}

有一个滑动窗口:

1)L是滑动窗口最左位置,R是滑动窗口最右位置,一开始LR都在数组左侧
2)任何一步都可能R往右移动表示某个数进了窗口
3)任何一步都可能L往右动,表示某个数出了窗口
想知道每一个窗口状态的中位数

还是想象有这样一个结构:
1)这个结构可以接收数字,也可以支持一个一个删除数也可以都删除
2)如果n等于奇数则取中间的数,如果为偶数则取中间两个数除以2
3)可以加入重复数字

public class SlidingWindowMedian {

	public static class SBTNode<K extends Comparable<K>> {
		public K key;
		public SBTNode<K> l;
		public SBTNode<K> r;
		public int size;

		public SBTNode(K k) {
			key = k;
			size = 1;
		}
	}

	public static class SizeBalancedTreeMap<K extends Comparable<K>> {
		private SBTNode<K> root;

		private SBTNode<K> rightRotate(SBTNode<K> cur) {
			SBTNode<K> leftNode = cur.l;
			cur.l = leftNode.r;
			leftNode.r = cur;
			leftNode.size = cur.size;
			cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
			return leftNode;
		}

		private SBTNode<K> leftRotate(SBTNode<K> cur) {
			SBTNode<K> rightNode = cur.r;
			cur.r = rightNode.l;
			rightNode.l = cur;
			rightNode.size = cur.size;
			cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
			return rightNode;
		}

		private SBTNode<K> maintain(SBTNode<K> cur) {
			if (cur == null) {
				return null;
			}
			int leftSize = cur.l != null ? cur.l.size : 0;
			int leftLeftSize = cur.l != null && cur.l.l != null ? cur.l.l.size : 0;
			int leftRightSize = cur.l != null && cur.l.r != null ? cur.l.r.size : 0;
			int rightSize = cur.r != null ? cur.r.size : 0;
			int rightLeftSize = cur.r != null && cur.r.l != null ? cur.r.l.size : 0;
			int rightRightSize = cur.r != null && cur.r.r != null ? cur.r.r.size : 0;
			if (leftLeftSize > rightSize) {
				cur = rightRotate(cur);
				cur.r = maintain(cur.r);
				cur = maintain(cur);
			} else if (leftRightSize > rightSize) {
				cur.l = leftRotate(cur.l);
				cur = rightRotate(cur);
				cur.l = maintain(cur.l);
				cur.r = maintain(cur.r);
				cur = maintain(cur);
			} else if (rightRightSize > leftSize) {
				cur = leftRotate(cur);
				cur.l = maintain(cur.l);
				cur = maintain(cur);
			} else if (rightLeftSize > leftSize) {
				cur.r = rightRotate(cur.r);
				cur = leftRotate(cur);
				cur.l = maintain(cur.l);
				cur.r = maintain(cur.r);
				cur = maintain(cur);
			}
			return cur;
		}

		private SBTNode<K> findLastIndex(K key) {
			SBTNode<K> pre = root;
			SBTNode<K> cur = root;
			while (cur != null) {
				pre = cur;
				if (key.compareTo(cur.key) == 0) {
					break;
				} else if (key.compareTo(cur.key) < 0) {
					cur = cur.l;
				} else {
					cur = cur.r;
				}
			}
			return pre;
		}

		private SBTNode<K> add(SBTNode<K> cur, K key) {
			if (cur == null) {
				return new SBTNode<K>(key);
			} else {
				cur.size++;
				if (key.compareTo(cur.key) < 0) {
					cur.l = add(cur.l, key);
				} else {
					cur.r = add(cur.r, key);
				}
				return maintain(cur);
			}
		}

		private SBTNode<K> delete(SBTNode<K> cur, K key) {
			cur.size--;
			if (key.compareTo(cur.key) > 0) {
				cur.r = delete(cur.r, key);
			} else if (key.compareTo(cur.key) < 0) {
				cur.l = delete(cur.l, key);
			} else {
				if (cur.l == null && cur.r == null) {
					// free cur memory -> C++
					cur = null;
				} else if (cur.l == null && cur.r != null) {
					// free cur memory -> C++
					cur = cur.r;
				} else if (cur.l != null && cur.r == null) {
					// free cur memory -> C++
					cur = cur.l;
				} else {
					SBTNode<K> pre = null;
					SBTNode<K> des = cur.r;
					des.size--;
					while (des.l != null) {
						pre = des;
						des = des.l;
						des.size--;
					}
					if (pre != null) {
						pre.l = des.r;
						des.r = cur.r;
					}
					des.l = cur.l;
					des.size = des.l.size + (des.r == null ? 0 : des.r.size) + 1;
					// free cur memory -> C++
					cur = des;
				}
			}
			return cur;
		}

		private SBTNode<K> getIndex(SBTNode<K> cur, int kth) {
			if (kth == (cur.l != null ? cur.l.size : 0) + 1) {
				return cur;
			} else if (kth <= (cur.l != null ? cur.l.size : 0)) {
				return getIndex(cur.l, kth);
			} else {
				return getIndex(cur.r, kth - (cur.l != null ? cur.l.size : 0) - 1);
			}
		}

		public int size() {
			return root == null ? 0 : root.size;
		}

		public boolean containsKey(K key) {
			if (key == null) {
				throw new RuntimeException("invalid parameter.");
			}
			SBTNode<K> lastNode = findLastIndex(key);
			return lastNode != null && key.compareTo(lastNode.key) == 0 ? true : false;
		}

		public void add(K key) {
			if (key == null) {
				throw new RuntimeException("invalid parameter.");
			}
			SBTNode<K> lastNode = findLastIndex(key);
			if (lastNode == null || key.compareTo(lastNode.key) != 0) {
				root = add(root, key);
			}
		}

		public void remove(K key) {
			if (key == null) {
				throw new RuntimeException("invalid parameter.");
			}
			if (containsKey(key)) {
				root = delete(root, key);
			}
		}

		public K getIndexKey(int index) {
			if (index < 0 || index >= this.size()) {
				throw new RuntimeException("invalid parameter.");
			}
			return getIndex(root, index + 1).key;
		}

	}

	public static class Node implements Comparable<Node> {
		public int index;
		public int value;

		public Node(int i, int v) {
			index = i;
			value = v;
		}

		@Override
		public int compareTo(Node o) {
			return value != o.value ? Integer.valueOf(value).compareTo(o.value)
					: Integer.valueOf(index).compareTo(o.index);
		}
	}

	public static double[] medianSlidingWindow(int[] nums, int k) {
		SizeBalancedTreeMap<Node> map = new SizeBalancedTreeMap<>();
		for (int i = 0; i < k - 1; i++) {
			map.add(new Node(i, nums[i]));
		}
		double[] ans = new double[nums.length - k + 1];
		int index = 0;
		for (int i = k - 1; i < nums.length; i++) {
			map.add(new Node(i, nums[i]));
			if (map.size() % 2 == 0) {
				Node upmid = map.getIndexKey(map.size() / 2 - 1);
				Node downmid = map.getIndexKey(map.size() / 2);
				ans[index++] = ((double) upmid.value + (double) downmid.value) / 2;
			} else {
				Node mid = map.getIndexKey(map.size() / 2);
				ans[index++] = (double) mid.value;
			}
			map.remove(new Node(i - k + 1, nums[i - k + 1]));
		}
		return ans;
	}

}

高效实现ArrayList的add(index,num),get(index),remove(index)方法要求时间复杂度为LogN

假设维持一棵树A左边出现的点的自然时序都比它早,然后A的右树自然时序都比A晚,S的自然时序都比B早,k的自然时序都比B晚
在这里插入图片描述

假设现在我们要左旋:
在这里插入图片描述
我的自然时序依然不变。

public class AddRemoveGetIndexGreat {

	public static class SBTNode<V> {
		public V value;
		public SBTNode<V> l;
		public SBTNode<V> r;
		public int size;

		public SBTNode(V v) {
			value = v;
			size = 1;
		}
	}

	public static class SbtList<V> {
		private SBTNode<V> root;

		private SBTNode<V> rightRotate(SBTNode<V> cur) {
			SBTNode<V> leftNode = cur.l;
			cur.l = leftNode.r;
			leftNode.r = cur;
			leftNode.size = cur.size;
			cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
			return leftNode;
		}

		private SBTNode<V> leftRotate(SBTNode<V> cur) {
			SBTNode<V> rightNode = cur.r;
			cur.r = rightNode.l;
			rightNode.l = cur;
			rightNode.size = cur.size;
			cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
			return rightNode;
		}

		private SBTNode<V> maintain(SBTNode<V> cur) {
			if (cur == null) {
				return null;
			}
			int leftSize = cur.l != null ? cur.l.size : 0;
			int leftLeftSize = cur.l != null && cur.l.l != null ? cur.l.l.size : 0;
			int leftRightSize = cur.l != null && cur.l.r != null ? cur.l.r.size : 0;
			int rightSize = cur.r != null ? cur.r.size : 0;
			int rightLeftSize = cur.r != null && cur.r.l != null ? cur.r.l.size : 0;
			int rightRightSize = cur.r != null && cur.r.r != null ? cur.r.r.size : 0;
			if (leftLeftSize > rightSize) {
				cur = rightRotate(cur);
				cur.r = maintain(cur.r);
				cur = maintain(cur);
			} else if (leftRightSize > rightSize) {
				cur.l = leftRotate(cur.l);
				cur = rightRotate(cur);
				cur.l = maintain(cur.l);
				cur.r = maintain(cur.r);
				cur = maintain(cur);
			} else if (rightRightSize > leftSize) {
				cur = leftRotate(cur);
				cur.l = maintain(cur.l);
				cur = maintain(cur);
			} else if (rightLeftSize > leftSize) {
				cur.r = rightRotate(cur.r);
				cur = leftRotate(cur);
				cur.l = maintain(cur.l);
				cur.r = maintain(cur.r);
				cur = maintain(cur);
			}
			return cur;
		}

		private SBTNode<V> add(SBTNode<V> root, int index, SBTNode<V> cur) {
			if (root == null) {
				return cur;
			}
			root.size++;
			int leftAndHeadSize = (root.l != null ? root.l.size : 0) + 1;
			if (index < leftAndHeadSize) {
				root.l = add(root.l, index, cur);
			} else {
				root.r = add(root.r, index - leftAndHeadSize, cur);
			}
			root = maintain(root);
			return root;
		}

		private SBTNode<V> remove(SBTNode<V> root, int index) {
			root.size--;
			int rootIndex = root.l != null ? root.l.size : 0;
			if (index != rootIndex) {
				if (index < rootIndex) {
					root.l = remove(root.l, index);
				} else {
					root.r = remove(root.r, index - rootIndex - 1);
				}
				return root;
			}
			if (root.l == null && root.r == null) {
				return null;
			}
			if (root.l == null) {
				return root.r;
			}
			if (root.r == null) {
				return root.l;
			}
			SBTNode<V> pre = null;
			SBTNode<V> suc = root.r;
			suc.size--;
			while (suc.l != null) {
				pre = suc;
				suc = suc.l;
				suc.size--;
			}
			if (pre != null) {
				pre.l = suc.r;
				suc.r = root.r;
			}
			suc.l = root.l;
			suc.size = suc.l.size + (suc.r == null ? 0 : suc.r.size) + 1;
			return suc;
		}

		private SBTNode<V> get(SBTNode<V> root, int index) {
			int leftSize = root.l != null ? root.l.size : 0;
			if (index < leftSize) {
				return get(root.l, index);
			} else if (index == leftSize) {
				return root;
			} else {
				return get(root.r, index - leftSize - 1);
			}
		}

		public void add(int index, V num) {
			SBTNode<V> cur = new SBTNode<V>(num);
			if (root == null) {
				root = cur;
			} else {
				if (index <= root.size) {
					root = add(root, index, cur);
				}
			}
		}

		public V get(int index) {
			SBTNode<V> ans = get(root, index);
			return ans.value;
		}

		public void remove(int index) {
			if (index >= 0 && size() > index) {
				root = remove(root, index);
			}
		}

		public int size() {
			return root == null ? 0 : root.size;
		}

	}

	// 通过以下这个测试,
	// 可以很明显的看到LinkedList的插入、删除、get效率不如SbtList
	// LinkedList需要找到index所在的位置之后才能插入或者读取,时间复杂度O(N)
	// SbtList是平衡搜索二叉树,所以插入或者读取时间复杂度都是O(logN)
	public static void main(String[] args) {
		// 功能测试
		int test = 50000;
		int max = 1000000;
		boolean pass = true;
		ArrayList<Integer> list = new ArrayList<>();
		SbtList<Integer> sbtList = new SbtList<>();
		for (int i = 0; i < test; i++) {
			if (list.size() != sbtList.size()) {
				pass = false;
				break;
			}
			if (list.size() > 1 && Math.random() < 0.5) {
				int removeIndex = (int) (Math.random() * list.size());
				list.remove(removeIndex);
				sbtList.remove(removeIndex);
			} else {
				int randomIndex = (int) (Math.random() * (list.size() + 1));
				int randomValue = (int) (Math.random() * (max + 1));
				list.add(randomIndex, randomValue);
				sbtList.add(randomIndex, randomValue);
			}
		}
		for (int i = 0; i < list.size(); i++) {
			if (!list.get(i).equals(sbtList.get(i))) {
				pass = false;
				break;
			}
		}
		System.out.println("功能测试是否通过 : " + pass);

		// 性能测试
		test = 500000;
		list = new ArrayList<>();
		sbtList = new SbtList<>();
		long start = 0;
		long end = 0;

		start = System.currentTimeMillis();
		for (int i = 0; i < test; i++) {
			int randomIndex = (int) (Math.random() * (list.size() + 1));
			int randomValue = (int) (Math.random() * (max + 1));
			list.add(randomIndex, randomValue);
		}
		end = System.currentTimeMillis();
		System.out.println("ArrayList插入总时长(毫秒) : " + (end - start));

		start = System.currentTimeMillis();
		for (int i = 0; i < test; i++) {
			int randomIndex = (int) (Math.random() * (i + 1));
			list.get(randomIndex);
		}
		end = System.currentTimeMillis();
		System.out.println("ArrayList读取总时长(毫秒) : " + (end - start));

		start = System.currentTimeMillis();
		for (int i = 0; i < test; i++) {
			int randomIndex = (int) (Math.random() * list.size());
			list.remove(randomIndex);
		}
		end = System.currentTimeMillis();
		System.out.println("ArrayList删除总时长(毫秒) : " + (end - start));

		start = System.currentTimeMillis();
		for (int i = 0; i < test; i++) {
			int randomIndex = (int) (Math.random() * (sbtList.size() + 1));
			int randomValue = (int) (Math.random() * (max + 1));
			sbtList.add(randomIndex, randomValue);
		}
		end = System.currentTimeMillis();
		System.out.println("SbtList插入总时长(毫秒) : " + (end - start));

		start = System.currentTimeMillis();
		for (int i = 0; i < test; i++) {
			int randomIndex = (int) (Math.random() * (i + 1));
			sbtList.get(randomIndex);
		}
		end = System.currentTimeMillis();
		System.out.println("SbtList读取总时长(毫秒) :  " + (end - start));

		start = System.currentTimeMillis();
		for (int i = 0; i < test; i++) {
			int randomIndex = (int) (Math.random() * sbtList.size());
			sbtList.remove(randomIndex);
		}
		end = System.currentTimeMillis();
		System.out.println("SbtList删除总时长(毫秒) :  " + (end - start));

	}

}

红黑树的基本概念

1)AVL树它的平衡性来自于左树及右树的高度差小于等于1
2)SB树任何一个叔叔节点的个数不小于侄子节点,保证节点较少的树和节点较大的树的数量不超过两倍以上

红黑树定义
1)每个节点不是红就是黑
2)整棵树的头节点一定是黑,叶节点也一定为黑
3)节点有黑有红的情况下两个红节点不能相邻
4)每一颗子树任何一条链黑节点的数量要一样
最长的链条一定是红黑相间的,最短的链一定是只有黑节点的,且长度不会超过两倍以上。此优点是防止像AVL树一样删除和增加节点的时候就马上调整平衡性。对于硬盘的IO消耗比较低
插入有5种情况,删除有8种情况。


http://www.kler.cn/a/156009.html

相关文章:

  • 实现一个BLE HID鼠标
  • 鸿蒙进阶篇-属性动画-animateTo转场动画
  • Linux探秘坊-------1.系统核心的低语:基础指令的奥秘解析(1)
  • 通过脚本,发起分支合并请求和打tag
  • mapreduce 将数据清洗后保存到 hbase
  • 准确--FastDFS快速单节点部署
  • 2023年GopherChina大会-核心PPT资料下载
  • Fiddler抓包工具之fiddler的常用快捷键
  • SpringAMQP入门案例——发送消息
  • Android CardView基础使用
  • 反序列化漏洞详解(三)
  • blender导出相机参数
  • ESP32使用mpu6050以及pid调参
  • Python - 字典3
  • 详解云WAF:免费GOODWAF归来
  • HarmonyOS—ArkTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化【鸿蒙专栏-11】
  • C语言实现Cohen_Sutherland算法
  • 构造函数的定义
  • Prometheus+Grafana搭建日志采集
  • Langchain-Chatchat的安装过程
  • C++基础 -35- string类
  • 操作系统·存储器管理
  • 亚信科技AntDB数据库完成中国信通院数据库迁移工具专项测试
  • unordered_map与unordered_set的实现(含迭代器)
  • go使用aes加密算法
  • 【ArcGIS Pro微课1000例】0043:深度学习--框架库安装