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

【188】Java8利用AVL树实现Map

AVL树又被叫做平衡二叉搜索树、平衡二叉树。AVL是其发明者的首字母缩写。

这篇文章中,AVLTreeMap 类集成了 java.util.Map 接口,并利用 AVL 树结构实现了 Map 接口的所有方法。本文还给出了测试代码。

为什么要发明AVL树?

当我按照从小到大或者从大到小的顺序向二叉查找树插入节点,二叉查找树就会退化成一个链表。这是二叉查找树的最差情况。搜索、插入、删除的最差效率都是 O(N)。这样就失去了用二叉查找树优化查找方法的意义。

就算不是最坏情况,也会出现非常不平衡的树,造成查找效率大于 O(logN) 小于 O(N) 。注意这里 logN 是以2为底N的对数。

AVL树的时间复杂度

因为含有数学公式,就使用图片了。
在这里插入图片描述

在这里插入图片描述

代码实现

AVLTreeMap.java


package zhangchao.avl;import java.util.*;/*** 利用AVL树,也就是平衡二叉树来实现map* @author zhangchao* @param <K> 键* @param <V> 值*/
public class AVLTreeMap<K,V> implements Map<K, V>{// 根节点private Node<K, V> root = null;private Comparator<K> comparator;public AVLTreeMap(Comparator<K> comparator) {this.comparator = comparator;}@Overridepublic int size() {if (null == root) {return 0;}int size = 0;// 当前层的节点列表List<Node<K, V>> currentLevel = new ArrayList<>();currentLevel.add(root);while (!currentLevel.isEmpty()) {size += currentLevel.size();// 下一层的节点列表List<Node<K, V>> nextLevel = new ArrayList<>();for (Node<K, V> tmpNode : currentLevel) {if (null != tmpNode.leftChild) {nextLevel.add(tmpNode.leftChild);}if (null != tmpNode.rightChild) {nextLevel.add(tmpNode.rightChild);}}currentLevel.clear();currentLevel.addAll(nextLevel);}return size;}@Overridepublic boolean isEmpty() {return (null == root);}@Overridepublic boolean containsKey(Object keyObj) {if (null == root) {return false;}K key = (K)keyObj;Node<K, V> current = this.root;while(null != current) {int compareResult = this.comparator.compare(key, current.key);if (compareResult < 0) {current = current.leftChild;} else if (compareResult > 0) {current = current.rightChild;} else {return true;}}return false;}@Overridepublic boolean containsValue(Object value) {if (null == this.root) {return false;}List<Node<K, V>> nodeList = this.nodeList();for (Node<K, V> node : nodeList) {if (null == value && null == node.value) {return true;}if (null != value && value.equals(node.value)) {return true;}}return false;}@Overridepublic V get(Object keyObj) {if (null == this.root) {return null;}K key = (K)keyObj;Node<K, V> current = this.root;while(null != current) {int compareResult = this.comparator.compare(key, current.key);if (compareResult < 0) {current = current.leftChild;} else if (compareResult > 0) {current = current.rightChild;} else {return current.value;}}return null;}/*** 右旋操作* @param parent 爷爷节点* @param y 父级节点* @param x 子级节点*/private void rotateRight(Node<K, V> parent, Node<K, V> y, Node<K, V> x) {y.leftChild = x.rightChild;x.rightChild = y;if (null == parent) {this.root = x;} else {// 判断原来的y是parent的左子节点还是右子节点。if (null != parent.leftChild && 0 == this.comparator.compare(parent.leftChild.key, y.key)) {parent.leftChild = x;} else if (null != parent.rightChild && 0 == this.comparator.compare(parent.rightChild.key, y.key)) {parent.rightChild = x;}}y.height = this.calHeight(y);x.height = this.calHeight(x);if (null != parent) {parent.height = this.calHeight(parent);}}/*** 左旋操作* @param parent 爷爷节点* @param y 父级节点* @param x 子级节点*/private void rotateLeft(Node<K, V> parent, Node<K, V> y, Node<K, V> x) {y.rightChild = x.leftChild;x.leftChild = y;if (null == parent) {this.root = x;} else {// 判断原来的y是parent的左子节点还是右子节点。if (null != parent.leftChild && 0 == this.comparator.compare(parent.leftChild.key, y.key)) {parent.leftChild = x;} else if (null != parent.rightChild && 0 == this.comparator.compare(parent.rightChild.key, y.key)) {parent.rightChild = x;}}y.height = this.calHeight(y);x.height = this.calHeight(x);if (null != parent) {parent.height = this.calHeight(parent);}}@Overridepublic V put(K key, V value) {if (null == this.root) {this.root = new Node<>();this.root.key = key;this.root.value = value;this.root.height = 1;return null;}// 如果key是全新的,保存所有的父亲节点。List<Node<K, V>> linkList = new ArrayList<>();// 如果key是全新的,这个变量是新节点的父亲节点。Node<K, V> parent = null;Node<K, V> current = root;int compareResult = 0;while (null != current) {compareResult = this.comparator.compare(key, current.key);if (compareResult < 0) {parent = current;linkList.add(parent);current = current.leftChild;} else if (compareResult > 0) {parent = current;linkList.add(parent);current = current.rightChild;} else {// 有相等的key,直接设置值就可以了。V oldValue = current.value;current.value = value;return oldValue;}}Node<K, V> newItem = new Node<K, V>();newItem.key = key;newItem.value = value;newItem.height = 1;if (compareResult < 0) {parent.leftChild = newItem;} else if (compareResult > 0) {parent.rightChild = newItem;}// 更新祖先节点的高度final int size = linkList.size();for (int i = size - 1; i >= 0; i--) {Node<K, V> item = linkList.get(i);item.height = calHeight(item);}linkList.add(newItem);int parentSize = linkList.size();for (int i = parentSize - 1; i >= 0; i--) {// 当前节点Node<K, V> z = linkList.get(i);// z的父节点,如果z是根节点,那么就是null。Node<K, V> z_parent = null;if (i > 0) {z_parent = linkList.get(i - 1);}int leftHeight = this.calHeight(z.leftChild);int rightHeight = this.calHeight(z.rightChild);int balance = leftHeight - rightHeight;if (balance > 1) { // LL 或 LRNode<K, V> y = z.leftChild;Node<K, V> x = linkList.get(i + 2);boolean isLL = (null != y.leftChild  && this.comparator.compare(y.leftChild.key, x.key) == 0);boolean isLR = (null != y.rightChild && this.comparator.compare(y.rightChild.key, x.key) == 0);if (isLL) { // LL 右旋this.rotateRight(z_parent, z, y);}else if (isLR) {    // LR// y和x之间左旋this.rotateLeft(z, y, x);// z和x之间右旋this.rotateRight(z_parent, z, x);}break; // 停止for循环} else if (balance < -1) { // RR 或 RLNode<K, V> y = z.rightChild;Node<K, V> x = linkList.get(i + 2);boolean isRR = (null != y.rightChild && this.comparator.compare(y.rightChild.key, x.key) == 0);boolean isRL = (null != y.leftChild && this.comparator.compare(y.leftChild.key, x.key) == 0);if (isRR) {this.rotateLeft(z_parent, z, y);} else if (isRL) {// y和x之间右旋this.rotateRight(z, y, x);// z和x之间左旋this.rotateLeft(z_parent, z, x);}break; // 停止for循环}}// 更新祖先节点高度for (int i = parentSize - 1; i >= 0; i--) {Node<K, V> item = linkList.get(i);item.height = calHeight(item);}return null;}private List<Node<K,V>> getNodeAndParent(K key, List<Node<K, V>> parents) {if (null == this.root) {return null;}Node<K, V> parent = null;Node<K, V> current = this.root;while(null != current) {int compareResult = this.comparator.compare(key, current.key);if (compareResult < 0) {parent = current;if (null != parents) {parents.add(parent);}current = current.leftChild;} else if (compareResult > 0) {parent = current;if (null != parents) {parents.add(parent);}current = current.rightChild;} else {List<Node<K, V>> result = new ArrayList<>();result.add(current);result.add(parent);return result;}}return null;}private K deleteAsBST(Node<K, V> node, Node<K, V> parent) {K endKey = null;// 叶子节点if (null == node.leftChild && null == node.rightChild) {if (node == parent.leftChild) {parent.leftChild = null;} else {parent.rightChild = null;}return parent.key;}// 左子节点为空,只有右子节点else if (null == node.leftChild && null != node.rightChild) {if (node == this.root) {this.root = node.rightChild;} else if (node == parent.leftChild) {parent.leftChild = node.rightChild;} else if (node == parent.rightChild) {parent.rightChild = node.rightChild;}endKey = node.rightChild.key;node.rightChild = null;return endKey;}// else 包含两种情况:// 1.左子节点不为空,右子为空// 2.左子节点不为空,右子不为空// 要删除的节点的左子树中,找出最大节点。Node<K, V> current = node.leftChild;Node<K, V> currentParent = node;while (null != current.rightChild) {currentParent = current;current = current.rightChild;}// 把current从原位置删除if (current == currentParent.leftChild) {currentParent.leftChild = current.leftChild;} else if (current == currentParent.rightChild) {currentParent.rightChild = current.leftChild;}// 让current取代node的位置if (node == this.root) {this.root = current;} else if (node == parent.leftChild) {parent.leftChild = current;} else {parent.rightChild = current;}current.leftChild = node.leftChild;current.rightChild = node.rightChild;node.leftChild = null;node.rightChild = null;if (null == current.leftChild) {return current.key;} else {Node<K, V> p1 = current.leftChild;while (null != p1.rightChild) {p1 = p1.rightChild;}return p1.key;}}@Overridepublic V remove(Object keyObj) {// 空map,不执行删除操作。if (null == this.root) {return null;}K key = (K)keyObj;// 只有根节点的情况if (null == this.root.leftChild && null == this.root.rightChild) {if (this.comparator.compare(key ,this.root.key) == 0) {V v = this.root.value;this.root = null;return v;} else {return null;}}// 不包含key就返回nullList<Node<K, V>> nodeAndParent = this.getNodeAndParent(key, new ArrayList<>());// map中没有对应的key,不执行删除操作。if (null == nodeAndParent || nodeAndParent.isEmpty()) {return null;}Node<K, V> node = nodeAndParent.get(0); // 要删除的节点V result = node.value;Node<K, V> parent = nodeAndParent.get(1); // 要删除的节点的父亲节点// 按照二叉搜索树(BST)的方式删除节点。返回结束节点的键。K endKey = this.deleteAsBST(node, parent);// 包含所有可能改动过高度的节点的列表。// 顺序是从根节点向下。// 替换了已删除节点位置的节点称为替换节点。// pathList的内容有以下三种情况:// 1. 叶子节点,pathList包含根节点到父节点。// 2. 没有左子节点,只有右子节点,pathList包含根节点到替换节点。// 3. 有左子节点,pathList包含根节点到替换节点,再加上替换节点到替换节点左子树最大节点。List<Node<K, V>> pathList = new ArrayList<>();List<Node<K,V>> endKeyResult = this.getNodeAndParent(endKey, pathList);pathList.add(endKeyResult.get(0));// 因为可能加入了节点,所以要重新计算 parents 的长度int size = pathList.size();for (int i = size - 1; i >= 0; i--) {Node<K, V> z_parent = i > 0 ? pathList.get(i - 1) : null;Node<K, V> z = pathList.get(i);// 更新高度z.height = this.calHeight(z);if (null != z_parent) {z_parent.height = this.calHeight(z_parent);}int leftHeight = calHeight(z.leftChild);int rightHeight = calHeight(z.rightChild);int balance = leftHeight - rightHeight;if (balance > 1) {Node<K, V> y = z.leftChild;Node<K, V> x = null;int y_leftHeight = calHeight(y.leftChild);int y_rightHeight = calHeight(y.rightChild);if (y_leftHeight >= y_rightHeight) {// LLx = y.leftChild;// z和y之间右旋this.rotateRight(z_parent, z, y);} else {// LRx = y.rightChild;// y和x之间左旋this.rotateLeft(z, y, x);// z和x之间右旋this.rotateRight(z_parent, z, x);}} else if (balance < -1) {Node<K, V> y = z.rightChild;Node<K, V> x = null;int y_leftHeight = calHeight(y.leftChild);int y_rightHeight = calHeight(y.rightChild);if (y_leftHeight >= y_rightHeight) {// RLx = y.leftChild;// y和x之间右旋this.rotateRight(z, y, x);// z和x之间左旋this.rotateLeft(z_parent, z, x);} else {// RRx = y.rightChild;// z和y之间左旋this.rotateLeft(z_parent, z, y);}}}return result;}// end public V remove(Object keyObj)@Overridepublic void putAll(Map<? extends K, ? extends V> m) {if (null == m) {return;}Set<? extends K> keySet = m.keySet();for (K key : keySet) {this.put(key, m.get(key));}}@Overridepublic void clear() {this.root = null;}private List<Node<K, V>> nodeList() {if (null == this.root) {return new ArrayList<Node<K, V>>();}List<Node<K, V>> result = new ArrayList<>();Stack<Node<K, V>> stack = new Stack<>();Node<K, V> current = this.root;while(null != current || !stack.isEmpty()) {while (null != current) {stack.push(current);current = current.leftChild;}current = stack.pop();// 放入结果列表中result.add(current);current = current.rightChild;}return result;}@Overridepublic Set<K> keySet() {List<Node<K, V>> nodeList = nodeList();Set<K> set = new TreeSet<>(this.comparator);for (Node<K, V> node : nodeList) {set.add(node.key);}return set;}@Overridepublic Collection<V> values() {List<Node<K, V>> nodeList = nodeList();List<V> result = new ArrayList<>();for (Node<K,V> node : nodeList) {result.add(node.value);}return result;}@Overridepublic Set<Entry<K, V>> entrySet() {List<Node<K, V>> nodeList = this.nodeList();Set<Entry<K, V>> set = new TreeSet<Entry<K, V>>((o1, o2) -> {Node<K, V> n1 = (Node<K, V>) o1;Node<K, V> n2 = (Node<K, V>) o2;return comparator.compare(n1.key, n2.key);});for (Node<K,V> node : nodeList) {set.add(node);}return set;}private int calHeightForCheck(Node<K,V> node) {if (null == node) {return 0;}int height = 0;List<Node<K,V>> currentLevel = new ArrayList<>();currentLevel.add(node);while (!currentLevel.isEmpty()) {height ++;List<Node<K,V>> nextLevel = new ArrayList<>();for (Node<K,V> tmpNode : currentLevel) {if (null != tmpNode.leftChild) {nextLevel.add(tmpNode.leftChild);}if (null != tmpNode.rightChild) {nextLevel.add(tmpNode.rightChild);}}currentLevel = nextLevel;}return height;}private void showTree(Node node, Node parent, int level, String prefix) {if (null == node) {return;}StringBuilder sb = new StringBuilder();for (int i = 0; i < level; i++) {sb.append("  ");}sb.append(prefix);sb.append(node.key).append("         ");if (parent != null) {sb.append(parent.key);}int balance = calHeightForCheck(node.leftChild) - calHeightForCheck(node.rightChild);sb.append("    ").append(balance);System.out.println(sb);level++;showTree(node.leftChild, node, level, "left : ");showTree(node.rightChild, node, level, "right: ");}/*** 打印树形结构。*/public void showTree() {if (null == root) {System.out.println("null");}showTree(root, null, 0, "root: ");}private void checkTree(Node node, Node parent, int level) {if (null == node) {return;}int balance = calHeightForCheck(node.leftChild) - calHeightForCheck(node.rightChild);if (balance < -1 || balance > 1) {throw new RuntimeException("balance < -1 || balance > 1");}level++;checkTree(node.leftChild, node, level);checkTree(node.rightChild, node, level);}/*** 检查树是不是符合AVL树的要求*/public void checkTree() {if (null == root) {return;}checkTree(root, null, 0);}/*** 以node为根节点,计算树的高度* @param node 根节点* @return 树的高度*/private int calHeight(Node<K,V> node) {if (null == node) {return 0;}int leftHeight = (null == node.leftChild) ? 0 : node.leftChild.height;int rightHeight = (null == node.rightChild) ? 0 : node.rightChild.height;return Math.max(leftHeight, rightHeight) + 1;}class Node<K,V> implements Entry<K,V> {K key = null;V value = null;int height;Node<K, V> leftChild;Node<K, V> rightChild;@Overridepublic K getKey() {return key;}@Overridepublic V getValue() {return value;}@Overridepublic V setValue(V tmpValue) {V oldValue = value;value = tmpValue;return oldValue;}public int getHeight() {return height;}}
}

测试代码 TestAVLTreeMap.java
这里面有和二叉查找树Map的对比。
二叉查找树Map的实现文章:https://blog.csdn.net/zhangchao19890805/article/details/128609922?spm=1001.2014.3001.5502


package zhangchao.avl.test;import zhangchao.avl.AVLTreeMap;import zhangchao.bst.BstTreeMap;import java.util.*;public class TestAVLTreeMap {public static void main(String[] args) {t7();}public static void t7() {int a[] = {20, 10, 21, 22, 5, 15, 1};Comparator<Integer> comparator = (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;};AVLTreeMap<Integer, String> avlTreeMap = new AVLTreeMap<>(comparator );for (int key : a) {avlTreeMap.put(key, "__" + key);}avlTreeMap.showTree();avlTreeMap.remove(20);System.out.println("\n");avlTreeMap.showTree();avlTreeMap.checkTree();}public static void t6() {Comparator<Integer> comparator = (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;};AVLTreeMap<Integer, String> avlTreeMap = new AVLTreeMap<>(comparator );BstTreeMap<Integer, String> bstTreeMap = new BstTreeMap<>(comparator);long t1;long t2;// 比对插入System.out.println("insert");Random r = new Random();final int MAX = 100000;List<Integer> list = new ArrayList<>();for (int i = 0; i < MAX; i++) {int key = r.nextInt(MAX);list.add(i);}t1 = System.currentTimeMillis();for (int key : list) {avlTreeMap.put(key, "__" + key);}t2 = System.currentTimeMillis();System.out.println("AVL:" + (t2 - t1));t1 = System.currentTimeMillis();for (int key : list) {bstTreeMap.put(key, "__" + key);}t2 = System.currentTimeMillis();System.out.println("BST:" + (t2 - t1));// 比对查询System.out.println("\nsearch");t1 = System.currentTimeMillis();for (int i = 0; i < MAX; i++) {avlTreeMap.get(i);}t2 = System.currentTimeMillis();System.out.println("AVL:" + (t2 - t1));t1 = System.currentTimeMillis();for (int i = 0; i < MAX; i++) {bstTreeMap.get(i);}t2 = System.currentTimeMillis();System.out.println("BST:" + (t2 - t1));
//        avlTreeMap.showTree();//      比对删除System.out.println("\nremove");t1 = System.currentTimeMillis();Collections.shuffle(list);for (int key : list) {avlTreeMap.remove(key);}t2 = System.currentTimeMillis();System.out.println("AVL:" + (t2 - t1));t1 = System.currentTimeMillis();for (int key : list) {bstTreeMap.remove(key);}t2 = System.currentTimeMillis();System.out.println("BST:" + (t2 - t1));avlTreeMap.checkTree();}public static void t3() {Map<Integer, String> map = new AVLTreeMap<>( (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;});int[] arr = new int[]{20,10,21,5,15,22,13,16};for (int i : arr) {map.put(i, "__" + String.valueOf(i));}AVLTreeMap avlTreeMap = (AVLTreeMap) map;avlTreeMap.showTree();avlTreeMap.remove(10);System.out.println("\n");avlTreeMap.showTree();avlTreeMap.checkTree();}public static void t2() {Map<Integer, String> map = new AVLTreeMap<>( (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;});int[] arr = new int[]{8,3,6,1,2,98,2,6,150,170,160,7,52,28,75,14,40,86,10,21,46,25};for (int i : arr) {map.put(i, "__" + String.valueOf(i));}AVLTreeMap avlTreeMap = (AVLTreeMap) map;avlTreeMap.showTree();avlTreeMap.remove(7);System.out.println("\n\n\n");avlTreeMap.showTree();avlTreeMap.checkTree();}public static void t1() {Map<Integer, String> map = new AVLTreeMap<>( (o1, o2) ->{if (null == o1 && null == o2) {return 0;}if (null == o1 && null != o2) {return -1;}if (null != o1 && null == o2) {return 1;}return o1 - o2;});int[] arr = new int[]{8,3,6,1,2,98,2,6,150,170,160,7,52,28,75,14,40,86,10,21,46,25};for (int i : arr) {map.put(i, "__" + String.valueOf(i));}AVLTreeMap avlTreeMap = (AVLTreeMap) map;avlTreeMap.showTree();System.out.println(map.get(3));System.out.println(map.get(6));System.out.println(map.get(98));System.out.println(map.get(null));Set<Integer> set = avlTreeMap.keySet();for (Integer i : set) {System.out.println(i);}System.out.println();HashSet<Integer> hashSet = new HashSet<>();for (int i : arr) {hashSet.add(i);}for (int i : hashSet) {if (!set.contains(i)) {System.out.println(false);}}System.out.println(set.size() + "   " + hashSet.size());System.out.println("containsKey 3: " + avlTreeMap.containsKey(3));System.out.println("containsKey 4: " + avlTreeMap.containsKey(4));System.out.println("containsValue __3: " + avlTreeMap.containsValue("__3"));System.out.println("containsValue __4: " + avlTreeMap.containsValue("__4"));System.out.println();Set<Map.Entry<Integer, String>> entrySet = avlTreeMap.entrySet();for (Map.Entry<Integer, String> item : entrySet) {System.out.println(item.getKey() + ": " + item.getValue());}avlTreeMap.checkTree();}
}

相关文章:

【188】Java8利用AVL树实现Map

AVL树又被叫做平衡二叉搜索树、平衡二叉树。AVL是其发明者的首字母缩写。 这篇文章中&#xff0c;AVLTreeMap 类集成了 java.util.Map 接口&#xff0c;并利用 AVL 树结构实现了 Map 接口的所有方法。本文还给出了测试代码。 为什么要发明AVL树&#xff1f; 当我按照从小到大…...

[SQL挖掘机] - 右连接: right join

介绍: 右连接是一种多表连接方式&#xff0c;它以右侧的表为基础&#xff0c;并返回满足连接条件的匹配行以及右侧表中的所有行&#xff0c;即使左侧的表中没有匹配的行。右连接将右表的每一行与左表进行比较&#xff0c;并根据连接条件返回结果集。其实, 左连接和右连接原理一…...

bug篇之基于docker安装nacos(2.1.1)使用dubbo连接不上的问题

说明&#xff1a;首先我的nacos安装是2.1.1版本&#xff0c;请注意版本问题。另外启动时用dubbo的话必须先启动服务提供者再启动服务使用者&#xff0c;否则会报错&#xff0c;同时也必须开放三个端口&#xff1a;8848&#xff0c;9848&#xff0c;9849 java.lang.IllegalStat…...

【Python入门系列】第二十一篇:Python物联网和传感器应用

文章目录 前言一、Python在物联网和传感器应用中的优势二、连接传感器和设备三、读取传感器数据四、示例代码和讲解五、进一步处理和分析传感器数据六、更多应用示例1、温湿度监测系统2、智能家居系统 - 灯光控制 总结 前言 物联网和传感器在现代科技中扮演着重要的角色。物联…...

Python爬虫的urlib的学习(学习于b站尚硅谷)

目录 一、页面结构的介绍  1.学习目标  2.为什么要了解页面&#xff08;html&#xff09;  3. html中的标签&#xff08;仅介绍了含表格、无序列表、有序列表、超链接&#xff09;  4.本节的演示 二、Urllib  1.什么是互联网爬虫&#xff1f;  2.爬虫核心  3.爬虫…...

【MongoDB】--MongoDB聚合Aggregation

目录 一、前言二、聚合管道操作2.1、实际案例1(1)、案例--根据学生no&#xff0c;找到对应班级名称(2)、案例--这个班级有哪些学生和哪些老师在任课 2.2、实际案例2(1)、案例--主表和关联表都有条件限制&#xff0c;且分页返回 一、前言 聚合操作组值来自多个文档&#xff0c;…...

Hadoop学习指南:探索大数据时代的重要组成——Hadoop概述

前言 在当今大数据时代&#xff0c;处理海量数据成为了一项关键任务。Hadoop作为一种开源的分布式计算框架&#xff0c;为大规模数据处理和存储提供了强大的解决方案。本文将介绍Hadoop的组成和其在大数据处理中的重要作用&#xff0c;让我们一同踏上学习Hadoop的旅程。 Hado…...

Java实现简单小画板

Java制作简单画板&#xff0c;包括两个类&#xff0c;一个主要画板类Drawpad&#xff0c;一个画板监听器DrawListener类。 1、Drawpad类&#xff0c;包括画板&#xff0c;画板功能设计&#xff0c;保存图片等 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 2…...

B078-项目实战--支付模块 领养订单支付流程

目录 支付模块需求分析表设计支付单表支付宝账号信息表-商家账号微信支付账号信息表-商家账号银行账号表-商家资金账号表支付流水表 流程分析支付基础模块继承加密算法沙箱环境准备支付宝支付-流程分析根据demo封装工具类导入依赖AlipayConfigAlipayInfoAlipayUtil 内网穿透 领…...

[css]margin-top不起作用问题(外边距合并)

在初学css时&#xff0c;会遇到突然间margin-top不起作用的情况。如下面&#xff1a; 情况一&#xff1a; 代码&#xff1a; <html> <head><style type"text/css"> * {margin:0;padding:0;border:0; }#outer {width:300px;height:300px;backgroun…...

Vue2基础八、插槽

零、文章目录 Vue2基础八、插槽 1、插槽 &#xff08;1&#xff09;默认插槽 作用&#xff1a;让组件内部的一些 结构 支持 自定义需求: 将需要多次显示的对话框, 封装成一个组件问题&#xff1a;组件的内容部分&#xff0c;不希望写死&#xff0c;希望能使用的时候自定义。…...

自然语言处理从入门到应用——LangChain:提示(Prompts)-[提示模板:连接到特征存储]

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 特征存储是传统机器学习中的一个概念&#xff0c;它确保输入模型的数据是最新和相关的。在考虑将LLM应用程序投入生产时&#xff0c;这个概念非常重要。为了个性化LLM应用程序&#xff0c;我们可能希望将LLM与特定用户…...

jenkins自定义邮件发送人姓名

jenkins发送邮件的时候发送人姓名默认的&#xff0c;如果要自定义发件人姓名&#xff0c;只需要修改如下信息即可&#xff1a; 系统管理-system-Jenkins Location下的系统管理员邮件地址 格式为&#xff1a;自定义姓名<邮件地址>...

SolidWorks二次开发---简单的连接solidworks

创建一个.net Framework的应用&#xff0c;正常4.0以上就可以了。 打开nuget包管理 在里面搜索paine 在版中选择对应的solidworks年份开头的&#xff0c;进行安装。 安装完之后 : 同时选中下面两个dll,把嵌入操作类型改为false 然后在按钮的单击事件中输入: Connect.Crea…...

docker 安装 active Mq

在安装完Docker的机器上&#xff0c;安装activeMQ。 拉取镜像&#xff1a; docker pull webcenter/activemq 查看镜像&#xff1a; docker images Docker运行ActiveMQ镜像 docker run --name activemq -d -p 8161:8161 -p 61616:61616 --privilegedtrue --restartalways …...

【Linux】TCP协议

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;TCP协议&…...

DevOps系列文章之 自动化测试大全(单测和集成测试)

自动化测试业界主流工具 核心目标&#xff1a; 主要是功能测试和覆盖率测试 业界常用主流工具 GoogleTest GoogleTest是一个跨平台的(Liunx、Mac OS X、Windows 、Cygwin 、Windows CE and Symbian ) C单元测试框架&#xff0c;由google公司发布&#xff0c;为在不同平台上为编…...

Android启动速度优化

本节主要内容&#xff1a;了解APP启动流程、启动状态、查看启动时间、CPU Profile定位启动耗时代码、StrictMode严苛模式检测不合理写法、解决启动黑白屏问题。 一、APP启动流程 ①用户点击桌面App图标&#xff0c;Launcher进程采用Binder IPC向system_server进程发起startAc…...

linux 日志 系统安全日志 web日志

web日志 LINUX日志系统之WEB日志&#xff08;一&#xff09;_dracut.log_麻子来了的博客-CSDN博客 系统安全日志 Linux系统安全日志详解_sinolover的博客-CSDN博客 wtmp和utmp文件都是二进制文件&#xff0c;需使用who、w、users、last和ac来操作这两个文件。 who /var/lo…...

SpringBoot 整合 MongoDB 连接 阿里云MongoDB

注&#xff1a;spring-boot-starter-data-mongodb 2.7.5&#xff1b;jdk 1.8 阿里云MongoDB是副本集实例的 在网上查找了一番&#xff0c;大多数都是教连接本地mongodb或者linux上的mongodb 阿里云上有java版连接教程&#xff0c;但它不是SpringBoot方法配置的&#xff0c;是手…...

终极指南:如何用ESP32-A2DP库快速构建蓝牙音频设备

终极指南&#xff1a;如何用ESP32-A2DP库快速构建蓝牙音频设备 【免费下载链接】ESP32-A2DP A Simple ESP32 Bluetooth A2DP Library (to implement a Music Receiver or Sender) that supports Arduino, PlatformIO and Espressif IDF 项目地址: https://gitcode.com/gh_mir…...

高通量细胞因子/生物因子检测技术介绍

高通量细胞因子/生物因子检测技术介绍—多维免疫分析技术&#xff0c;赋能精准医学与转化研究 导语 伴随精准医学领域持续深耕与转化医学研究的高速推进&#xff0c;细胞因子、趋化因子、生长因子等各类可溶性生物标志物的动态表达变化&#xff0c;成为解析疾病发病机制、研判…...

转行简历不会衔接?AI一键生成,自然过渡无违和感,邀约率飙升3倍!

“我以前是做销售的&#xff0c;想转行产品经理&#xff0c;简历上怎么写才能不让HR觉得我风马牛不相及&#xff1f;” “干了几年运营&#xff0c;现在想尝试开发&#xff0c;简历里除了写熟悉Word、Excel&#xff0c;还能写啥&#xff1f;” “裸辞转行&#xff0c;简历一片…...

ai内容创作团队如何通过taotoken统一管理多个模型的调用

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 AI 内容创作团队如何通过 Taotoken 统一管理多个模型的调用 应用场景类&#xff0c;聚焦于 AI 内容生成团队&#xff0c;成员使用不…...

14100开源难题解榜141期:5道前沿技术难题完整收录|后续五期分步保姆级落地开源方案

开源难题解榜141期&#xff1a;5道前沿技术难题完整收录&#xff5c;后续五期分步保姆级落地开源方案 摘要 本文完整原样提取黄大年茶思屋难题解榜第141期全部五道硬核技术原题、技术背景、现存痛点、当前技术成果与详细技术诉求&#xff0c;不作内容删减与修改。本篇定为题目抽…...

3个步骤让你的Switch Joy-Con在Windows上焕发新生:JoyCon-Driver完全指南

3个步骤让你的Switch Joy-Con在Windows上焕发新生&#xff1a;JoyCon-Driver完全指南 【免费下载链接】JoyCon-Driver A vJoy feeder for the Nintendo Switch JoyCons and Pro Controller 项目地址: https://gitcode.com/gh_mirrors/jo/JoyCon-Driver 你是否曾想过让闲…...

通过Taotoken的CLI工具一键配置Python开发环境

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 通过Taotoken的CLI工具一键配置Python开发环境 对于希望快速开始使用大模型API的Python开发者而言&#xff0c;手动配置API密钥、B…...

Unity+C#开发MMO服务端的务实架构与万人连接实战

1. 先泼一盆冷水&#xff1a;所谓“万人同时在线”的真实含义与常见误解 很多人看到“UnityC#开发万人MMO服务器”这个标题&#xff0c;第一反应是&#xff1a;哇&#xff0c;这得用多牛的分布式架构&#xff1f;是不是要上Kubernetes集群、分库分表、消息中间件全配齐&#xf…...

让Windows 11任务栏唱歌:Taskbar-Lyrics插件如何改变你的音乐体验

让Windows 11任务栏唱歌&#xff1a;Taskbar-Lyrics插件如何改变你的音乐体验 【免费下载链接】Taskbar-Lyrics BetterNCM插件&#xff0c;在任务栏上嵌入歌词&#xff0c;目前仅建议Windows 11 项目地址: https://gitcode.com/gh_mirrors/ta/Taskbar-Lyrics 还在为切换…...

Allegro16.6 矩形槽孔焊盘 说明

铣刀实际直径 对应 mil 值 ncroutebits.txt 写法 输出 rou 里自动变成 0.60 mm 23.62 mil 23.62 T01 T01C.02362 0.65 mm 25.59 mil 25.59 T01 T01C.02559 0.70 mm 27.56 mil 27.56 T01 T01C.02756 0.80 mm 31.50 mil 31.50 T01 …...