数据结构--集合与映射(九)

以下是学习恋上数据结构与算法的记录,本篇主要内容是集合与映射

◼集合(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);
			}
		});
	}
}

猜你喜欢

转载自blog.csdn.net/qq_44961149/article/details/104774879