二分搜索树与映射

1. 映射的定义:映射就是存储( 键,值 )数据对的数据结构( Key,Value ) , 根据键(Key),寻找值(Value), 可以由链表实现映射LinkedMap ,是有序的;也可以由二分搜索树实现映射TreeMap,是有序的,并且键自然排序。映射中的键具有唯一性,不能重复;而键对应的值可以重复

2. 映射接口的定义:

public interface Map<K, V> {
	
	//向map中添加键值对
	public void put(K key, V value);
	
	//删除map中指定key的键值对
	public V remove(K key);
	
	//判断二分搜索树中是否包含指定key
	public boolean contains(K key);
	
	//通过key从map中获取key对应的值
	public V get(K key);
	
	//修改指定key对应的值
	public void set(K key, V value);
	
	//获取map中有效元素的个数
	public int size();
	
	//判断map是否为空
	public boolean isEmpty();
	
	//获取map中的键的集合 因为map中键key是唯一的 所以用集合set进行存储
	public Set<K> keySet();
	
	//获取map中的值的列表 因为map中键value不是唯一的 所以用列表list进行存储
	public List<V> values();
	
	//获取map中键值对的集合 因为map中键值对(key:value)是唯一的 所以用集合set进行存储
	public Set<Entry<K, V>> entrySet();
	
	//定义一个获取键值对Entry<K, V>的接口
	public interface Entry<K, V> extends Comparable<Entry<K, V>>{
		
		//获取键值对的键
		public K getKey();
		
		//获取键值对的值
		public V getValue();
		
		
	}
}

3. 底层通过二分搜索树实现的映射:( 许多操作类似于二分搜索树,但是不能完全使用二分搜索树,因为二分搜索树中存储的节点只有一个数据域,而映射需要包含两个数据一个是键,一个是键对应的值 )。

//定义底层通过二分搜索树实现的映射map 
//二分搜索树中的数据必须具有可比性 因此映射中的键必须都是Comparable实现子类 因为键具有唯一性
public class TreeeMap<K extends Comparable<K>, V> implements Map<K, V>{
	
	//定义二分搜索树节点的信息 
	//由四部分组成 键 值 指向左孩子的指针 指向右孩子的指针
	private class Node {
		K key; //键
		V value; //值
		Node leftChild; //左孩子指针域 指向当前节点左孩子
		Node rightChild; //右孩子指针域 指向当前节点右孩子
		
		public Node() {}
		
		public Node(K key, V value) {
			this.key = key;
			this.value = value;
			this.leftChild = null;
			this.rightChild = null;
		}
	}

	private Node root; //根节点的指针 如果二分搜索树为空 则root==null
	
	private int size; //二分搜索树中元素的个数(键值对的个数)
	
	public TreeeMap() {
		root = null;
		size = 0;
	}
	
	//辅助方法 获取以node为根节点的二分搜索树中 键为key的节点
	private Node getNode(Node node, K key) {
		if(node == null) {
			return null;
		}
		if(key.compareTo(node.key) < 0) {
			return getNode(node.leftChild, key);
		}else if(key.compareTo(node.key) > 0) {
			return getNode(node.rightChild, key);
		}else {
			return node;
		}
	}
	
	//向map中添加键值对 向外提供的
	@Override
	public void put(K key, V value) {
		root = put(root, key, value);
		
	}

	//向以node为根节点的二分搜索树中添加指定键值对 如果已经存在 则修改指定key的值为value
	private Node put(Node node, K key, V value) {
		if(node == null) {
			size++;
			return new Node(key, value);
		}
		if(key.compareTo(node.key) < 0) {
			node.leftChild = put(node.leftChild, key, value);
		}else if(key.compareTo(node.key) > 0) {
			node.rightChild = put(node.rightChild, key, value);
		}else {
			node.value = value;
		}
		return node;
	}

	//删除map中指定key的键值对 并返回要删除键的值 向外提供的
	@Override
	public V remove(K key) {
		Node ret = getNode(root, key);
		if(ret == null) {
			return null;
		}
		root = remove(root, key);
		return ret.value;
	}

	//删除以node为根节点的二分搜索树中指定键值对
	private Node remove(Node node, K key) {
		if(node == null) {
			return null;
		}
		if(key.compareTo(node.key) < 0) {
			node.leftChild = remove(node.leftChild, key);
			return node;
		}else if(key.compareTo(node.key) > 0) {
			node.rightChild = remove(node.rightChild, key);
			return node;
		}else {
			if(node.leftChild == null) {
				Node rightNode = node.rightChild;
				node.rightChild = null;
				size--;
				return rightNode;
			}else if(node.rightChild == null) {
				Node leftNode = node.leftChild;
				node.leftChild = null;
				size--;
				return leftNode;
			}
			Node successor = getMinNum(root);
			successor.rightChild = removeMin(root);
			successor.leftChild = node.leftChild;
			node.leftChild = node.rightChild = null;
			return successor;
		}
	}

	//删除以node为根节点的二分搜索树的最小值
	private Node removeMin(Node node) {
		if(node.leftChild == null) {
			Node rightNode = node.rightChild;
			node.rightChild = null;
			size--;
			return rightNode;
		}
		node.leftChild = removeMin(node.leftChild);
		return node;
	}

	//获取以node为根节点的二分搜索树的最小值
	private Node getMinNum(Node node) {
		if(node.leftChild == null) {
			return node;
		}
		return getMinNum(node.leftChild);
	}

	//判断二分搜索树中是否包含指定key
	@Override
	public boolean contains(K key) {
		return getNode(root, key) != null;
	}

	//通过key从map中获取key对应的值
	@Override
	public V get(K key) {
		Node node = getNode(root, key);
		if(node == null) {
			throw new IllegalArgumentException("key is not exist");
		}
		return node.value;
	}

	//修改指定key对应的值
	@Override
	public void set(K key, V value) {
		Node node = getNode(root, key);
		if(node == null) {
			throw new IllegalArgumentException("key-value is not exist");
		}
		node.value = value;
	}

	//获取map中有效元素的个数
	@Override
	public int size() {
		return size;
	}

	//判断map是否为空
	@Override
	public boolean isEmpty() {
		return size == 0 && root == null;
	}

	//获取map中的键的集合 因为map中键key是唯一的 所以用集合set进行存储
	@Override
	public Set<K> keySet() {
		TreeSet<K> set = new TreeSet<K>();
		inOrderKeySet(root, set);
		return set;
	}

	//中序遍历以node节点为根节点的二分搜索树中的键 并将结果存放在指定集合set中
	private void inOrderKeySet(Node node, TreeSet<K> set) {
		if(node == null) {
			return;
		}
		inOrderKeySet(node.leftChild, set);
		set.add(node.key);
		inOrderKeySet(node.rightChild, set);
	}

	//获取map中的值的列表 因为map中键value不是唯一的 所以用列表list进行存储
	@Override
	public List<V> values() {
		LinkedList<V> list = new LinkedList<V>();
		inOrderValues(root, list);
		return list;
	}

	//中序遍历以node节点为根节点的二分搜索树的值 并将结果存放在指定列表list中
	private void inOrderValues(Node node, LinkedList<V> list) {
		if(node == null) {
			return;
		}
		inOrderValues(node.leftChild, list);
		list.add(node.value);
		inOrderValues(node.rightChild, list);
	}

	//获取map中键值对的集合 因为map中键值对(key:value)是唯一的 所以用集合set进行存储
	@Override
	public Set<Entry<K, V>> entrySet() {
		TreeSet<Entry<K, V>> set = new TreeSet<Entry<K,V>>();
		inOrderEntries(root, set);
		return set;
	}

	//中序遍历以node节点为根节点的二分搜索树的键值对 并将结果存放在指定集合set中
	private void inOrderEntries(Node node, TreeSet<Entry<K, V>> set) {
		if(node == null) {
			return;
		}
		inOrderEntries(node.leftChild, set);
		set.add(new BSTEntry(node.key, node.value));
		inOrderEntries(node.rightChild, set);
	}

	//定义一个获取键值对Entry<K, V>的实现类 来封装键值对
	/*
	 * 用treeSet来存储键值对 treeSet底层又是通过二分搜索树实现的
	 * 因此treeSet存储的内容必须具有可比性 所以键值对的实现类中必须重写compareTo方法
	 * 键值对中的键又要具有可比性 因此键也要继承于Comparable
	 */
	private class BSTEntry<K extends Comparable<K>, V> implements Entry<K, V>{

		public K key;
		public V value;
		
		public BSTEntry(K key, V value) {
			this.key = key;
			this.value = value;
		}
		
		@Override
		public K getKey() { //获取键值对的键
			return key;
		}

		@Override
		public V getValue() { //获取键值对的值
			return value;
		}
		
		//规定键的比较规则
		@Override
		public int compareTo(Entry<K, V> o) {
			return this.key.compareTo(o.getKey());
		}
		
		//规定键值对的输出格式
		@Override
		public String toString() {
			return key + ":" + value;
		}
	}
	
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值