数据结构实现 5.1:映射_基于树实现(C++版)

1. 概念及基本框架

映射 是一种高级数据结构,其实现方法也不唯一,但存储上使用 链式存储(即内存的物理空间是不连续的)。这一节我们通过 二分搜索树 来实现映射这种数据结构。

映射
映射 的基本特性:
1.映射内元素包含 键(key)值(value) ,而且一一对应。
2.映射内的元素的键 不能重复
注:有些映射(多重映射)中元素的键也可以重复。
显然,二分搜索树满足映射的特性,所以我们尝试利用二分搜索树来实现映射。但是,在 3.1 中实现的二分搜索树结点只有一个数据,所以我们需要从底层进行一些改进去适应映射这一数据结构。首先来定义树的结点类:

template <class K, class V>
class MapBSTNode{
public:
	MapBSTNode(K key = NULL, V value = NULL, MapBSTNode<K, V> *left = NULL, MapBSTNode<K, V> *right = NULL){
		m_key = key;
		m_value = value;
		this->left = left;
		this->right = right;
	}
public:
	K m_key;
	V m_value;
	MapBSTNode<K, V> *left;
	MapBSTNode<K, V> *right;
};

这个结点类的内部也显式的给出了构造函数,下面通过结点类来创建一棵二叉树。这个过程和 3.1 中二分搜索树的实现过程类似,所以不再赘述,如有需要可参看 3.1

template <class K, class V>
class MapBST{
public:
	MapBST(){
		root = NULL;
	}
	...
private:
	MapBSTNode<K, V> *root;
	int m_size;
};

为了满足映射操作的需求,我为这个类定义了几个接口函数,实现方法与 3.1 类似,所以同样不再赘述。

template <class K, class V>
class MapBST{
public:
	...
	int size(){
		return m_size;
	}
	bool isEmpty(){
		return root == NULL;
	}
	//增加操作
	void add(K key, V value){
		root = add(root, key, value);
	}
	//删除操作
	V remove(K key){
		V res = get(key);
		root = remove(root, key);
		return res;
	}
	//修改操作
	void set(K key, V value){
		MapBSTNode<K, V> *node = root;
		while (node){
			if (key == node->m_key){
				node->m_value = value;
				return;
			}
			else if (key < node->m_key){
				node = node->left;
			}
			else{
				node = node->right;
			}
		}
		cout << "不存在" << key << '!' << endl;
		return;
	}
	//查找操作
	V get(K key){
		MapBSTNode<K, V> *node = root;
		while (node){
			if (key == node->m_key){
				return node->m_value;
			}
			else if (key < node->m_key){
				node = node->left;
			}
			else{
				node = node->right;
			}
		}
		cout << "不存在" << key << '!' << endl;
		return NULL;
	}
	bool contains(K key){
		return contains(root, key);
	}
private:
	MapBSTNode<K, V>* add(MapBSTNode<K, V> *node, K key, V value){
		if (node == NULL){
			m_size++;
			return new MapBSTNode<K, V>(key, value);
		}
		else if (key < node->m_key){
			node->left = add(node->left, key, value);
		}
		else if (key > node->m_key){
			node->right = add(node->right, key, value);
		}
		return node;
	}
	MapBSTNode<K, V>* remove(MapBSTNode<K, V> *node, K key){
		if (node == NULL){
			return node;
		}
		if (key < node->m_key){
			node->left = remove(node->left, key);
		}
		else if (key > node->m_key){
			node->right = remove(node->right, key);
		}
		else if (key == node->m_key){
			if (node->left == NULL){
				MapBSTNode<K, V> *rightNode = node->right;
				delete node;
				m_size--;
				return rightNode;
			}
			else if (node->right == NULL){
				MapBSTNode<K, V> *leftNode = node->left;
				delete node;
				m_size--;
				return leftNode;
			}
			else{
				MapBSTNode<K, V> *minNode = node->right;
				for (; minNode->left; minNode = minNode->left);
				node->m_key = minNode->m_key;
				node->right = remove(node->right, minNode->m_key);
				return node;
			}
		}
		return node;
	}
	bool contains(MapBSTNode<K, V> *node, K key){
		if (node == NULL){
			return false;
		}
		if (key == node->m_key){
			return true;
		}
		else if (key < node->m_key){
			return contains(node->left, key);
		}
		else{
			return contains(node->right, key);
		}
	}
	...
};

有了改进版的二分搜索树,我们就可以利用一个由 纯虚函数 构成的 抽象类 作为一个接口来定义这些操作。具体代码如下:

template <class K, class V>
class Map{
public:
	virtual int size() = 0;
	virtual bool isEmpty() = 0;
	//增加操作
	virtual void add(K key, V value) = 0;
	//删除操作
	virtual V remove(K key) = 0;
	//修改操作
	virtual void set(K key, V value) = 0;
	//查找操作
	virtual bool contains(K key) = 0;
	virtual V get(K key) = 0;
};

下面只需要通过继承 抽象类,并且重写 纯虚函数 ,就可以完成 映射 的实现。映射类的框架如下:

template <class K, class V>
class BSTMap : public Map<K, V>{
	...
private:
	MapBST<K, V> bst;
};

这里为了避免重复设计就可以兼容更多数据类型,引入了 泛型 ,即 模板 的概念。(模板的关键字是 classtypename
这里的 bst 表示一棵 二分搜索树 ,同样,为了保护数据,变量设置为 private
注:这里没有显式的给出构造函数,因为子类中除了二分搜索树对象之外没有特别需要初始化的东西。编译器会默认先调用 二分搜索树 类(即父类)的构造函数,再去调用 映射 类(即子类)的构造函数。
实现了前面的程序之后,接下来就是一个映射的增、删、改、查以及一些其他基本操作,接下来利用代码去实现。

2. 基本操作程序实现

2.1 增加操作

template <class K, class V>
class BSTMap : public Map<K, V>{
public:
	...
	//增加操作
	void add(K key, V value){
		bst.add(key, value);
	}
	...
};

直接调用二分搜索树的增加操作。(因为二分搜索树中的元素本来就不重复)

2.2 删除操作

template <class K, class V>
class BSTMap : public Map<K, V>{
public:
	...
	//删除操作
	V remove(K key){
		return bst.remove(key);
	}
	...
};

直接调用二分搜索树的删除操作。

2.3 修改操作

template <class K, class V>
class BSTMap : public Map<K, V>{
public:
	...
	//修改操作
	void set(K key, V value){
		bst.set(key, value);
	}
	...
};

2.4 查找操作

template <class K, class V>
class BSTMap : public Map<K, V>{
public:
	...
	//查找操作
	bool contains(K key){
		return bst.contains(key);
	}
	V get(K key){
		return bst.get(key);
	}
	...
};

2.5 其他操作

映射还有一些其他的操作,包括 映射大小 的查询等操作。

template <class K, class V>
class BSTMap : public Map<K, V>{
public:
	int size(){
		return bst.size();
	}
	bool isEmpty(){
		return bst.isEmpty();
	}
	...
};

3. 算法复杂度分析

因为映射操作直接调用了二分搜索树的操作,所以其操作的时间复杂度和二分搜索树相同。

3.1 增加操作

函数 最坏复杂度 平均复杂度
add O(n) O(logn)

3.2 删除操作

函数 最坏复杂度 平均复杂度
remove O(n) O(logn)

3.3 修改操作

函数 最坏复杂度 平均复杂度
set O(n) O(logn)

3.4 查找操作

函数 最坏复杂度 平均复杂度
contains O(n) O(logn)
get O(n) O(logn)

总体情况:

操作 时间复杂度
O(logn)
O(logn)
O(logn)
O(logn)

很显然,利用二分搜索树很容易实现映射这一高级数据结构。

4. 完整代码

程序完整代码(这里使用了头文件的形式来实现类)如下。
二分搜索树 类代码:

#ifndef __MAPBST_H__
#define __MAPBST_H__

template <class K, class V>
class MapBSTNode{
public:
	MapBSTNode(K key = NULL, V value = NULL, MapBSTNode<K, V> *left = NULL, MapBSTNode<K, V> *right = NULL){
		m_key = key;
		m_value = value;
		this->left = left;
		this->right = right;
	}
public:
	K m_key;
	V m_value;
	MapBSTNode<K, V> *left;
	MapBSTNode<K, V> *right;
};
template <class K, class V>
class MapBST{
public:
	MapBST(){
		root = NULL;
	}
	int size(){
		return m_size;
	}
	bool isEmpty(){
		return root == NULL;
	}
	//增加操作
	void add(K key, V value){
		root = add(root, key, value);
	}
	//删除操作
	V remove(K key){
		V res = get(key);
		root = remove(root, key);
		return res;
	}
	//修改操作
	void set(K key, V value){
		MapBSTNode<K, V> *node = root;
		while (node){
			if (key == node->m_key){
				node->m_value = value;
				return;
			}
			else if (key < node->m_key){
				node = node->left;
			}
			else{
				node = node->right;
			}
		}
		cout << "不存在" << key << '!' << endl;
		return;
	}
	//查找操作
	V get(K key){
		MapBSTNode<K, V> *node = root;
		while (node){
			if (key == node->m_key){
				return node->m_value;
			}
			else if (key < node->m_key){
				node = node->left;
			}
			else{
				node = node->right;
			}
		}
		cout << "不存在" << key << '!' << endl;
		return NULL;
	}
	bool contains(K key){
		return contains(root, key);
	}
private:
	MapBSTNode<K, V>* add(MapBSTNode<K, V> *node, K key, V value){
		if (node == NULL){
			m_size++;
			return new MapBSTNode<K, V>(key, value);
		}
		else if (key < node->m_key){
			node->left = add(node->left, key, value);
		}
		else if (key > node->m_key){
			node->right = add(node->right, key, value);
		}
		return node;
	}
	MapBSTNode<K, V>* remove(MapBSTNode<K, V> *node, K key){
		if (node == NULL){
			return node;
		}
		if (key < node->m_key){
			node->left = remove(node->left, key);
		}
		else if (key > node->m_key){
			node->right = remove(node->right, key);
		}
		else if (key == node->m_key){
			if (node->left == NULL){
				MapBSTNode<K, V> *rightNode = node->right;
				delete node;
				m_size--;
				return rightNode;
			}
			else if (node->right == NULL){
				MapBSTNode<K, V> *leftNode = node->left;
				delete node;
				m_size--;
				return leftNode;
			}
			else{
				MapBSTNode<K, V> *minNode = node->right;
				for (; minNode->left; minNode = minNode->left);
				node->m_key = minNode->m_key;
				node->right = remove(node->right, minNode->m_key);
				return node;
			}
		}
		return node;
	}
	bool contains(MapBSTNode<K, V> *node, K key){
		if (node == NULL){
			return false;
		}
		if (key == node->m_key){
			return true;
		}
		else if (key < node->m_key){
			return contains(node->left, key);
		}
		else{
			return contains(node->right, key);
		}
	}
private:
	MapBSTNode<K, V> *root;
	int m_size;
};

#endif

抽象类 接口代码:

#ifndef __MAP_H__
#define __MAP_H__

template <class K, class V>
class Map{
public:
	virtual int size() = 0;
	virtual bool isEmpty() = 0;
	//增加操作
	virtual void add(K key, V value) = 0;
	//删除操作
	virtual V remove(K key) = 0;
	//修改操作
	virtual void set(K key, V value) = 0;
	//查找操作
	virtual bool contains(K key) = 0;
	virtual V get(K key) = 0;
};

#endif

映射类 代码:

#ifndef __BSTMAP_H__
#define __BSTMAP_H__

#include "Map.h"
#include "MapBST.h"

template <class K, class V>
class BSTMap : public Map<K, V>{
public:
	int size(){
		return bst.size();
	}
	bool isEmpty(){
		return bst.isEmpty();
	}
	//增加操作
	void add(K key, V value){
		bst.add(key, value);
	}
	//删除操作
	V remove(K key){
		return bst.remove(key);
	}
	//修改操作
	void set(K key, V value){
		bst.set(key, value);
	}
	//查找操作
	bool contains(K key){
		return bst.contains(key);
	}
	V get(K key){
		return bst.get(key);
	}
private:
	MapBST<K, V> bst;
};

#endif

猜你喜欢

转载自blog.csdn.net/qq_35481167/article/details/84025991