以下是学习恋上数据结构与算法的记录,本篇主要内容是集合与映射
◼集合(Set)
●集合的特点
●不存放重复的元素
●常用于去重
✓存放新增IP,统计新增IP 量
✓存放词汇,统计词汇量
思考:集合的内部实现能否直接利用以前学过的数据结构?
动态数组、链表、二叉搜索树(AVL树、红黑树)。
集合的接口设计
●链表实现set
public class ListSet<E> implements Set<E> {
private List<E> list = new LinkedList<>();
//数量
public int size() {
return list.size();
}
public boolean isEmpty() {
return list.isEmpty();
}
public void clear() {
list.clear();
}
public boolean contains(E element) {
return list.contains(element);
}
//去重
public void add(E element) {
int index=list.indexOf(element);
if(index != list.ELEMENT_NOT_FOUND) {//存在就覆盖 去重
list.set(index, element);
}else {
list.add(element);
}
}
public void remove(E element) {
int index=list.indexOf(element);
if (index != List.ELEMENT_NOT_FOUND) {//如果存在就删除
list.remove(index);
}
}
public void traversal(Visitor<E> visitor) {
if(visitor==null) return;
int size = list.size();
for(int i = 0 ; i<size;i++) {
if (visitor.visit(list.get(i))) return;
}
}
}
●红黑树实现treeSet
public class TreeSet<E> implements Set<E>{
private RBTree<E> tree;
public TreeSet() {
this(null);
}
//因为红黑树的元素需要可比较性
public TreeSet(Comparator<E>Comparator){
tree = new RBTree<>();
}
public int size() {
return tree.size();
}
public boolean isEmpty() {
return tree.isEmpty();
}
public void clear() {
tree.clear();
}
public boolean contains(E element) {
return tree.contains(element);
}
@Override
public void add(E element) {
tree.add(element);
}
@Override
public void remove(E element) {
tree.remove(element);
}
@Override
public void traversal(Visitor<E> visitor) {
tree.inorder(new BinaryTree.Visitor<E>() {
@Override
public boolean visit(E element) {
return visitor.visit(element);
}
});
}
◼映射(Map)
●Map 在有些编程语言中也叫做字典(dictionary,比如Python、Objective-C、Swift 等)
Map 将键映射到值的对象,键值对。
◼Map 的每一个key 是唯一的
Map的接口设计
类似Set,Map 可以直接利用之前学习的链表、二叉搜索树(AVL树、红黑树)等数据结构来实现
红黑树实现treeMap
<K,V>,键的数据结构是红黑树,可保证键的排序和唯一性。
需加上之前红黑树的旋转辅助等。`
public class TreeMap<K,V> implements Map<K, V> {
private static final boolean RED = false;
private static final boolean BLACK = true;
private int size;//数量
private Node<K,V> root;//根节点
private Comparator<K> comparator;//比较器
public TreeMap() {//红黑树的元素要有可比较性
this(null);
}
public TreeMap(Comparator<K> comparator) {
this.comparator = comparator;
}
public int size() {//数量
return size;
}
public boolean isEmpty() {
return size==0;
}
public void clear() {
size=0;
root=null;
}
public V put(K key, V value) {//添加
//判断key是否为空,空抛出异常
keyNotNullCheck(key);
//添加的第一个节点
if(root==null) {
root = new Node<>(key, value, null);
size++;
// 新添加节点之后的处理
afterPut(root);
return null;
}
// 添加的不是第一个节点
// 找到父节点
Node<K, V> parent = root;
Node<K, V> node = root;
int cmp=0;
do {
cmp = compare(key, node.key);
parent = node;
if(cmp>0) {
node=node.right;
}else if(cmp<0) {
node=node.left;
}else {//相等
node.key=key;
V oldValue=node.value;
node.value=value;
return oldValue;
}
}while(node!=null);
// 看看插入到父节点的哪个位置
Node<K, V> newNode = new Node<>(key, value, parent);
if(cmp>0) {
parent.right = newNode;
}else {
parent.left = newNode;
}
// 新添加节点之后的处理
afterPut(newNode);//红黑树的方法
return null;
}
public V get(K key) {/得到元素
Node<K, V> node = node(key);
return node!=null?node.value:null;
}
public V remove(K key) {//删除
return remove(node(key));//红黑树的方法
}
public boolean containsKey(K key) {//是否存在某元素
return node(key)!=null;
}
public boolean containsValue(V value) {//是否存在某值
if(root ==null) return false;
Queue<Node<K, V>> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
Node<K, V> node = queue.poll();
if(valEquals(value, node.value)) return true;
if (node.left!=null) {
queue.offer(node.left);
}
if (node.right!=null) {
queue.offer(node.right);
}
}
return false;
}
@Override
public void traversal(Visitor<K, V> visitor) {//遍历外部接口
if (visitor==null) return;
traversal(root,visitor);
}
private void traversal(Node<K, V> node, Visitor<K, V> visitor) {//遍历实现
if (node==null || visitor==null) return;
traversal(node.left,visitor);
if (visitor.stop) return;
visitor.visit(node.key, node.value);
traversal(node.right, visitor);
}
private boolean valEquals(V v1,V v2) {//判断两值是否相等
return v1==null?v2 ==null:v1.equals(v2);
}
private V remove(Node<K, V> node) {//删除实现
if (node == null) return null;
size--;
V oldValue = node.value;
if (node.hasTwoChildren()) { // 度为2的节点
// 找到后继节点
Node<K, V> s = successor(node);
// 用后继节点的值覆盖度为2的节点的值
node.key = s.key;
node.value = s.value;
// 删除后继节点
node = s;
}
// 删除node节点(node的度必然是1或者0)
Node<K, V> replacement = node.left != null ? node.left : node.right;
if (replacement != null) { // node是度为1的节点
// 更改parent
replacement.parent = node.parent;
// 更改parent的left、right的指向
if (node.parent == null) { // node是度为1的节点并且是根节点
root = replacement;
} else if (node == node.parent.left) {
node.parent.left = replacement;
} else { // node == node.parent.right
node.parent.right = replacement;
}
// 删除节点之后的处理
afterRemove(replacement);
} else if (node.parent == null) { // node是叶子节点并且是根节点
root = null;
} else { // node是叶子节点,但不是根节点
if (node == node.parent.left) {
node.parent.left = null;
} else { // node == node.parent.right
node.parent.right = null;
}
// 删除节点之后的处理
afterRemove(node);//红黑树的方法
}
return oldValue;
}
private Node<K, V> node(K key) {//得到node节点方法
Node<K, V> node = root;
while (node != null) {
int cmp = compare(key, node.key);
if (cmp == 0) return node;
if (cmp > 0) {
node = node.right;
} else { // cmp < 0
node = node.left;
}
}
return null;
}
private int compare(K e1, K e2) {//比较器实现
if (comparator != null) {
return comparator.compare(e1, e2);
}
return ((Comparable<K>)e1).compareTo(e2);
}
private void keyNotNullCheck(K key) {//检查key是否为空
if (key == null) {//不允许key为空
throw new IllegalArgumentException("key must not be null");
}
}
private static class Node<K,V> {//node节点类
K key;
V value;
boolean color = RED;
Node<K,V> left;
Node<K,V> right;
Node<K,V> parent;
public Node(K key, V value, Node<K, V> parent) {
this.key = key;
this.value = value;
this.parent = parent;
}
//。。。红黑树辅助方法
}
Map与Set
◼Map 的所有key 组合在一起,其实就是一个Set
◼因此,Set 可以间接利用Map 来作内部实现
public class MapTreeSet<E> implements Set<E>{
Map<E,Object> map = new TreeMap<>();
public int size() {
return map.size();
}
public boolean isEmpty() {
return map.isEmpty();
}
public void clear() {
map.clear();
}
public boolean contains(E element) {
return map.containsKey(element);
}
public void add(E element) {//关键点就是key存储element值,value为空
map.put(element, null);
}
public void remove(E element) {
map.remove(element);
}
public void traversal(Visitor<E> visitor) {
map.traversal(new Map.Visitor<E, Object>() {
@Override
public boolean visit(E key, Object value) {
return visitor.visit(key);
}
});
}
}