1. 程式人生 > >資料結構實現 5.1:對映_基於樹實現(C++版)

資料結構實現 5.1:對映_基於樹實現(C++版)

資料結構實現 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 
            
           

相關推薦

資料結構實現 5.1對映_基於實現C++

資料結構實現 5.1:對映_基於樹實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 修改操作 2.4 查詢操作 2.5 其他操作 3. 演算法複

資料結構實現 5.2對映_基於連結串列實現C++

資料結構實現 5.2:對映_基於連結串列實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 修改操作 2.4 查詢操作 2.5 其他操作 3. 演

資料結構實現 10.2對映_基於AVL實現C++

資料結構實現 10.2:對映_基於AVL樹實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 修改操作 2.4 查詢操作 2.5 其他操作 3.

資料結構實現 4.1集合_基於二分搜尋實現C++

資料結構實現 4.1:集合_基於二分搜尋樹實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

資料結構實現 9.1並查集_陣列結構實現C++

資料結構實現 9.1:並查集_陣列結構實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 聯合操作 2.2 查詢操作 2.3 其他操作 3. 演算法複雜度分析 3.1 聯合操作

資料結構實現 6.1二叉堆_基於動態陣列實現C++

資料結構實現 6.1:二叉堆_基於動態陣列實現(C++版) 1. 概念及基本框架 1.1 滿二叉樹 1.2 完全二叉樹 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 查詢操作

資料結構實現 8.1字典C++

資料結構實現 8.1:字典樹(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 查詢操作 2.3 其他操作 3. 演算法複雜度分析 3.1 增加操作 3.2 查

資料結構實現 6.4優先佇列_基於連結串列實現C++

資料結構實現 6.4:優先佇列_基於連結串列實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入隊操作 2.2 出隊操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

資料結構實現 6.3優先佇列_基於動態陣列實現C++

資料結構實現 6.3:優先佇列_基於動態陣列實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入隊操作 2.2 出隊操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

資料結構實現 6.2優先佇列_基於最大二叉堆實現C++

資料結構實現 6.2:優先佇列_基於最大二叉堆實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入隊操作 2.2 出隊操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

資料結構實現 4.2集合_基於連結串列實現C++

資料結構實現 4.2:集合_基於連結串列實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析

資料結構實現 3.1二分搜尋C++

資料結構實現 3.1:二分搜尋樹(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 查詢操作 2.4 遍歷操作 2.5 其他操作 3. 演算法複雜度分

資料結構實現 10.1AVLC++

資料結構實現 10.1:AVL樹(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.1.1 左左 2.1.2 右右 2.1.3 左右 2.1.4 右左 2.1

資料結構實現 9.2並查集_思想實現C++

資料結構實現 9.2:並查集_樹思想實現(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 聯合操作 2.2 查詢操作 2.3 其他操作 3. 演算法複雜度分析 3.1 聯合操作

資料結構5.1 順序表的查詢以及二分查詢的實現

類的結構如下: class StaticSearchTable { private: int *data; int data_number; bool search_seq(int loc,int key); void select_sort(); bool f

資料結構實現 2.1連結串列C++

1. 概念及基本框架 連結串列 是一種 線性結構 ,而且儲存上屬於 鏈式儲存(即記憶體的物理空間是不連續的),是線性表的一種。連結串列結構如下圖所示: 下面以一個我實現的一個簡單的連結串列類來進一步理解連結串列。 template <class T&g

資料結構實現連結串列棧C++

資料結構實現(六):連結串列棧(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入棧操作 2.2 出棧操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析 3.1

資料結構實現連結串列C++

資料結構實現(五):連結串列(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 增加操作 2.2 刪除操作 2.3 修改操作 2.4 查詢操作 2.5 其他操作 3. 演算法複雜度分析

資料結構實現迴圈佇列C++

資料結構實現(四):迴圈佇列(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入隊操作 2.2 出隊操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析 3.1 入

資料結構實現陣列佇列C++

資料結構實現(三):陣列佇列(C++版) 1. 概念及基本框架 2. 基本操作程式實現 2.1 入隊操作 2.2 出隊操作 2.3 查詢操作 2.4 其他操作 3. 演算法複雜度分析 3.1 入