自定义映射(Map)

版权声明:转载请注明出处: https://blog.csdn.net/qq_34774655/article/details/85337439

通过学习自定义映射,了解映射的数据结构。

本篇分别以链表的方式和以二分搜索树的方式实现了映射。

首先写一个映射的接口,描述其具有的基本功能。Map.java

然后写一个接口的实现类:

其中,方式一: 用的是链表的方式。 LinkedListMap.java

方式二:用的是二分搜索树的方式。  BSTMap.java


 

方式一与方式二的时间复杂度分析:

其中:  字母h代表树的深度。

    

 

LinkedListMap

BSTMap                平均情况                     最坏情况

add

O(n)

O(h)

O(log n)

O(n)

contains

O(n)

O(h)

O(log n)

O(n)

remove

O(n)

O(h)

O(log n)

O(n)

set

O(n)

O(h)

O(log n)

O(n)

get

O(n)

O(h)

O(log n)

O(n)

此外还分:有序映射、无序映射、多重映射。

 

有序映射:元素中的键具有顺序性。(基于搜索树的实现)

无序映射:元素中的键没有顺序性。(基于哈希表的实现)

多重映射:元素中的键可以重复。

Map.java

package SetAndMap;

public interface Map<K,V>{
	void add(K key,V value);//键不可重复
	
	boolean contains(K key);
	
	V remove(K key);
	
	V get(K key);
	
    void set(K key, V newValue);
    
	int getSize();
	
	boolean isEmpty();

}

方式一:

package SetAndMap;

public class LinkedListMap<K,V> implements Map<K,V> {
	/**
	 * 内部类
	 * 描述节点信息
	 * @author xiaohua
	 *
	 */
	private class Node{
		public K key;
		public V value;
		public Node next;
		
		public Node(K key,V value,Node next) {
			this.key=key;
			this.value=value;
			this.next=next;
		}
		
		public Node(K key,V value) {
			this(key,value,null);
		}
		
		public Node() {
			this(null,null,null);
			
		}
		@Override
		public String toString() {
			return key.toString()+" : "+value.toString();
		}
	}
	
	
	private Node dummyHead;//虚拟头结点
	private int size;//映射的大小
	/**
	 * 无参构造函数
	 * 初始化一个虚拟头节点,它的key、value都为null
	 */
	public LinkedListMap() {
		dummyHead=new Node();
		size=0;
	}
	/**
	 * 内部的一个辅助函数,以下的添加、修改等方法都依赖于此。
	 * 作用:获取当前键所对应的节点。若无,则返回null。
	 * @param key
	 * @return
	 */
	private Node getNode(K key) {
		Node cur=dummyHead.next;
		while(cur!=null) {
			
			if(cur.key.equals(key)) {
				return cur;
			}
			cur=cur.next;
			
		}
		return null;
		
	}
	/**
	 * 往映射中添加元素。若已存在该键,则修改value值
	 */
	@Override
	public void add(K key, V value) {
		Node node =getNode(key);
		
		if(node==null) {
			dummyHead.next=new Node(key,value,dummyHead.next);
			size++;
		}else {
			node.value=value;
		}	
		
	}
	/**
	 * 判断映射中是否已存在该键
	 */
	@Override
	public boolean contains(K key) {
		Node node =getNode(key);
		
		return node!=null;
	}

	
	/**
	 * 获取键所对应的value
	 */
	@Override
	public V get(K key) {
		Node node =getNode(key);
		return node==null? null:node.value;
	}
	/**
	 * 修改键所对应的值
	 */
	@Override
	public void set(K key, V newValue) {
		Node node =getNode(key);
		if(node == null)
            throw new IllegalArgumentException(key + " 不存在");
		node.value=newValue;
		
	}
	/**
	 * 删除指定的键,并返回键所对应的值
	 */
	@Override
	public V remove(K key) {
		Node  pre=dummyHead;
		while(pre.next !=null) {
			if(pre.next.key.equals(key)) {
				break;
			}
			pre=pre.next;
		}
		if(pre.next!=null) {
			
			Node delNode=pre.next;
			pre.next=delNode.next;
			delNode.next=null;
			size--;
			return delNode.value;
			
		}
		
		return null;
	}
	/**
	 * 返回映射的大小
	 */
	@Override
	public int getSize() {
		
		return size;
	}
	/**
	 * 判断映射是否为空
	 */
	@Override
	public boolean isEmpty() {
		
		return size==0;
	}

}

方式二:

package SetAndMap;



public class BSTMap<K extends Comparable<K>,V> implements Map<K,V> {
	/**
	 * 内部类
	 * 描述节点信息
	 * @author xiaohua
	 *
	 */
	private class Node{
		public K key;
		public V value;
		public Node left;
		public Node right;
		
		public Node(K key,V value) {
			this.key=key;
			this.value=value;
			this.left=null;
			this.right=null;
		}
		

	}
	
	
	private Node root;//根节点
	private int size;//映射的大小
	/**
	 * 无参构造函数
	 * 
	 */
	public BSTMap() {
		root=null;
		size=0;
	}
	/**
	 * 内部的一个辅助函数,以下的获取、判断、修改等方法都依赖于此。
	 * 作用:返回以node为根节点的二分搜索树中,key所在的节点
	 * @param 
	 * @return
	 */
	private Node getNode(Node node,K key) {
		if(node==null) {
			return null;
		}
		if(key.equals(node.key)) {
			return node;
		}else if(key.compareTo(node.key)<0) {
			return getNode(node.left,key);
		}else{
			return getNode(node.right ,key);
		}
		
		
	}
	/**
	 * 往映射中添加元素。若已存在该键,则修改value值
	 */
	@Override
	public void add(K key, V value) {
		root=add(root,key ,value);
		
	}
	/**
	 * 向以node为根的二分搜索树中插入元素(key, value),递归算法
    *返回插入新节点后二分搜索树的根
	 * @param node
	 * @param key
	 * @param value
	 * @return
	 */
	private Node add(Node node, K key, V value) {
		if(node==null) {
			size++;
			return new Node(key,value);
		}
		
		if(key.compareTo(node.key )<0 ) {
			
			node.left=add(node.left,key,value);
			
		}else if(key.compareTo(node.key )>0) {
			node.right=add(node.right,key,value);
		}else {
			node.value=value;//若已存在键,则修改相应的值
			
		}
		return node;
		
	}
	/**
	 * 判断映射中是否已存在该键
	 */
	@Override
	public boolean contains(K key) {
		Node node =getNode(root,key);
		
		return node!=null;
	}

	
	/**
	 * 获取键所对应的value
	 */
	@Override
	public V get(K key) {
		Node node =getNode(root,key);
		return node==null? null:node.value;
	}
	/**
	 * 修改键所对应的值
	 */
	@Override
	public void set(K key, V newValue) {
		Node node =getNode(root,key);
		if(node == null)
            throw new IllegalArgumentException(key + " 不存在");
		node.value=newValue;
		
	}
	/**
	 * 返回以node为根的二分搜索树的最小值所在的节点
	 * @param node
	 * @return
	 */
    private Node minimum(Node node){
        if(node.left == null)
            return node;
        return minimum(node.left);
    }

    /**
     * 删除掉以node为根的二分搜索树中的最小节点
     *  返回删除节点后新的二分搜索树的根
     */
    
    private Node removeMin(Node node){

        if(node.left == null){
            Node rightNode = node.right;
            node.right = null;
            size --;
            return rightNode;
        }

        node.left = removeMin(node.left);
        return node;
    }
	/**
	 * 删除指定的键,并返回键所对应的值
	 */
	@Override
	public V remove(K key) {
		
		Node node=getNode(root,key);
		
		if(node!=null) {
			root=remove(root,key);
			return node.value;
		}
		return null;
	}
	private Node remove(Node node, K key) {
		
		if(node==null) {
			return null;
		}
		if(key.compareTo(node.key )<0) {
			
			node.left=remove(node.left ,key);
			return node;
			
		}else if(key.compareTo(node.key )<0){
			
			node.right=remove(node.right ,key);
			return node;
		}else {// key.compareTo(node.key) == 0
			// 待删除节点左子树为空的情况
			if(node.left==null) {
				Node rightNode=node.right;
				node.right=null;
				size--;
				return rightNode;
				
			}
			// 待删除节点右子树为空的情况
			if(node.right==null) {
				
				Node leftNode=node.left;
				node.left=null;
				size--;
				return leftNode;
				
			}
			// 待删除节点左右子树均不为空的情况

            // 找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点
            // 用这个节点顶替待删除节点的位置
			Node successor=minimum(node.right);
			successor.right=removeMin(node.right);
			successor.left=node.left;
			
			node.left=node.right=null;
			return successor;
			
		}
		
		
	}
	/**
	 * 返回映射的大小
	 */
	@Override
	public int getSize() {
		
		return size;
	}
	/**
	 * 判断映射是否为空
	 */
	@Override
	public boolean isEmpty() {
		
		return size==0;
	}

}

猜你喜欢

转载自blog.csdn.net/qq_34774655/article/details/85337439