当前位置:   article > 正文

【数据结构】Set和Map(常用方法、手动实现)_set map

set map

目录

一、基本概念

二、二叉搜索树

三、手动实现

总结


一、基本概念

        Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。Set我们可以理解为集合,Map我们可以理解为字典。其中Set继承自collection接口,Map独立存在。Set中的基本元素为Key。Map中的基本元素为Key-value对。无论在Set还是在Map中,Key的值都不允许重复

        Map和Set可以通过什么来实现呢?我们也可以通过List来实现,但是我们发现效率太低,于是我们引出两种经典的数据结构以实现Set和Map。分别是二叉搜索树(Binary Search Tree)和哈希表(Hash Table)。其中二叉搜索树我们比较熟悉。

Set接口:

方法解释
void clear()清空集合
boolean add(E e)添加元素,但重复元素不会被添加成功
boolean contains(Object o)判断 o 是否在集合中
boolean remove(Object o)删除集合中的 o
int size()返回set中元素的个数
boolean isEmpty()检测set是否为空,空返回true,否则返回false
Iterator iterator() 返回迭代器
Object[] toArray()将set中的元素转换为数组返回
boolean containsAll(Collection c) 集合c中的元素是否在set中全部存在,是返回true,否则返回 false
boolean addAll(Collection c) 将集合c中的元素添加到set中,可以达到去重的效果

对于Set的两种实现方式比较

Set底层结构TreeSetHashSet
底层结构红黑树哈希桶
插入/删除/查找时间 复杂度O(log n)O(1)
是否有序关于Key有序不一定有序
线程安全不安全不安全
插入/删除/查找区别按照红黑树的特性来进行插入和删除1. 先计算key哈希地址 2. 然后进行 插入和删除
比较与覆写key必须能够比较,否则会抛出 ClassCastException异常自定义类型需要覆写equals和 hashCode方法
应用场景需要Key有序场景下Key是否有序不关心,需要更高的 时间性能

Map接口:

方法解释
V get(Object key)返回 key 对应的 value
V getOrDefault(Object key, V defaultValue)返回 key 对应的 value,key 不存在,返回默认值
V put(K key, V value)设置 key 对应的 value
V remove(Object key)删除 key 对应的映射关系
Set keySet() 返回所有 key 的不重复集合
Collection values() 返回所有 value 的可重复集合
Set<Map.Entry<K,V>> entrySet()返回所有的 key-value 映射关系
boolean containsKey(Object key)判断是否包含 key
boolean containsValue(Object value)判断是否包含 value

对于Map的两种实现方式的比较

Map底层结构TreeMapHashMap
底层结构红黑树哈希桶
插入/删除/查找时间 复杂度O(log n)O(1)
是否有序关于Key有序无序
线程安全不安全不安全
插入/删除/查找区别需要进行元素比较通过哈希函数计算哈希地址
比较与覆写key必须能够比较,否则会抛出 ClassCastException异常自定义类型需要覆写equals和 hashCode方法
应用场景需要Key有序场景下Key是否有序不关心,需要更高的 时间性能

二、二叉搜索树

二叉搜索树满足如下性质:

        1、若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

        2、 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

        3、它的左右子树也分别为二叉搜索树

三、手动实现

        我们自定义一个TreeNode类方便我们手动实现,我们只是对一些简单的基础功能进行实现,实现的结果如下:

  1. package set_map.set.treeSet;
  2. public class TreeNode {
  3. int key;
  4. TreeNode left;
  5. TreeNode right;
  6. public TreeNode(int key) {
  7. this.key = key;
  8. }
  9. @Override
  10. public String toString() {
  11. return "TreeNode{" +
  12. "key=" + key +
  13. ", left=" + left +
  14. ", right=" + right +
  15. '}';
  16. }
  17. }
  1. package set_map.set.treeSet;
  2. public class BSTree {
  3. private TreeNode root=null;
  4. public boolean contains(int dest){
  5. TreeNode cur=root;
  6. while (cur!=null){
  7. if(cur.key==dest){
  8. return true;
  9. }else if(cur.key<dest){
  10. cur=cur.right;
  11. }else{
  12. cur=cur.left;
  13. }
  14. }
  15. return false;
  16. }
  17. //给定顺序不同,得到的搜索树的结构也不同
  18. public boolean add(int dest){
  19. TreeNode treeNode = new TreeNode(dest);
  20. TreeNode parent=null;//定义一个节点用于记录双亲结点
  21. if(root==null){
  22. root=treeNode;
  23. return true;
  24. }
  25. TreeNode cur=root;
  26. while(cur!=null){
  27. if(cur.key==dest){
  28. return false;
  29. }else if(dest<cur.key){
  30. parent=cur;
  31. cur=cur.left;
  32. }else {
  33. parent=cur;
  34. cur=cur.right;
  35. }
  36. }
  37. //此时到了null的位置,是插入的时候了
  38. if(dest<parent.key){
  39. parent.left=treeNode;
  40. }else {
  41. parent.right=treeNode;
  42. }
  43. return true;
  44. }
  45. public boolean remove(int key){
  46. TreeNode parent=null;
  47. TreeNode cur=root;
  48. while(cur!=null){
  49. if(cur.key==key){
  50. deleteKey(parent,cur,key);
  51. return true;
  52. }else if(key< cur.key){
  53. parent=cur;
  54. cur=cur.left;
  55. }else{
  56. parent=cur;
  57. cur=cur.right;
  58. }
  59. }
  60. return false;
  61. }
  62. private void deleteKey(TreeNode parent,TreeNode node, int key) {
  63. if(node.left==null){
  64. if(node==root){
  65. root=root.right;
  66. }else if(node==parent.left){
  67. parent.left=node.right;
  68. }else{
  69. parent.right=node.right;
  70. }
  71. }else if(node.right==null){
  72. if(node==root){
  73. root=root.left;
  74. }else if(node==parent.left){
  75. parent.left=node.left;
  76. }else {
  77. parent.left=node.left;
  78. }
  79. }else{
  80. replaceDelete(parent,node);
  81. }
  82. }
  83. private void replaceDelete(TreeNode parent, TreeNode node) {
  84. TreeNode canparent=node;
  85. TreeNode candidate =node.left;
  86. while (candidate.right!=null){
  87. canparent=candidate;
  88. candidate=candidate.right;
  89. }
  90. //将值进行替换
  91. node.key= candidate.key;
  92. //删除候选人的节点
  93. if(canparent==node){
  94. canparent.left=candidate.left;
  95. }else {
  96. canparent.right=null;
  97. }
  98. }
  99. public static void main(String[] args) {
  100. int[] keys={9,7,13,21,5,8,16,32,4,0,1,6,2,3};
  101. BSTree bsTree = new BSTree();
  102. for (int key : keys) {
  103. bsTree.add(key);
  104. }
  105. System.out.println(true);
  106. int[] re={2,6,7,13,9};
  107. for (int i : re) {
  108. bsTree.remove(i);
  109. }
  110. System.out.println(true);
  111. }
  112. }

总结

        这些方法一定要牢记于心。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/570895
推荐阅读
相关标签
  

闽ICP备14008679号