資料結構實現 10.2:對映_基於AVL樹實現(C++版)
資料結構實現 10.2:對映_基於AVL樹實現(C++版)
1. 概念及基本框架
對映 是一種高階資料結構,其實現方法也不唯一,但儲存上使用 鏈式儲存(即記憶體的物理空間是不連續的)。這一節我們通過 AVL樹
對映 的基本特性:
1.對映內元素包含 鍵(key) 和 值(value) ,而且一一對應。
2.對映內的元素的鍵 不能重複 。
注:有些對映(多重對映)中元素的鍵也可以重複。
顯然,AVL樹滿足對映的特性,所以我們嘗試利用AVL樹來實現對映。
首先,我們可以利用一個由 純虛擬函式 構成的 抽象類 作為一個介面來定義這些操作。具體程式碼如下:
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 AVLTreeMap : public Map< K, V>{
...
private:
AVLTree<K, V> avl;
};
這裡為了避免重複設計就可以相容更多資料型別,引入了 泛型 ,即 模板 的概念。(模板的關鍵字是 class 或 typename)
這裡的 avl 表示一棵 AVL樹 ,同樣,為了保護資料,變數設定為 private 。
注:這裡沒有顯式的給出建構函式,因為子類中除了AVL樹物件之外沒有特別需要初始化的東西。編譯器會預設先呼叫 AVL樹 類(即父類)的建構函式,再去呼叫 對映 類(即子類)的建構函式。
實現了前面的程式之後,接下來就是一個對映的增、刪、改、查以及一些其他基本操作,接下來利用程式碼去實現。
2. 基本操作程式實現
2.1 增加操作
template <class K, class V>
class AVLTreeMap : public Map<K, V>{
public:
...
//增加操作
void add(K key, V value){
avl.add(key, value);
}
...
};
直接呼叫AVL樹的增加操作。(因為AVL樹中的元素本來就不重複)
2.2 刪除操作
template <class K, class V>
class AVLTreeMap : public Map<K, V>{
public:
...
//刪除操作
V remove(K key){
V res = avl.get(key);
avl.remove(key);
return res;
}
...
};
直接呼叫AVL樹的刪除操作。
2.3 修改操作
template <class K, class V>
class AVLTreeMap : public Map<K, V>{
public:
...
//修改操作
void set(K key, V value){
avl.add(key, value);
}
...
};
2.4 查詢操作
template <class K, class V>
class AVLTreeMap : public Map<K, V>{
public:
...
//查詢操作
bool contains(K key){
return avl.contains(key);
}
V get(K key){
return avl.get(key);
}
...
};
2.5 其他操作
對映還有一些其他的操作,包括 對映大小 的查詢等操作。
template <class K, class V>
class AVLTreeMap : public Map<K, V>{
public:
int size(){
return avl.size();
}
bool isEmpty(){
return avl.isEmpty();
}
...
};
3. 演算法複雜度分析
因為對映操作直接呼叫了AVL樹的操作,所以其操作的時間複雜度和AVL樹相同。
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) |
很顯然,利用AVL樹很容易實現對映這一高階資料結構。
4. 完整程式碼
程式完整程式碼(這裡使用了標頭檔案的形式來實現類)如下。
這裡不再給出AVL樹的實現,如有需要,可參看 10.1 。
抽象類 介面程式碼:
#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 __AVLTREEMAP_H__
#define __AVLTREEMAP_H__
#include "Map.h"
#include "AVLTree.h"
template <class K, class V>
class AVLTreeMap : public Map<K, V>{
public:
int size(){
return avl.size();
}
bool isEmpty(){
return avl.isEmpty();
}
//增加操作
void add(K key, V value){
avl.add(key, value);
}
//刪除操作
V remove(K key){
V res = avl.get(key);
avl.remove(key);
return res;
}
//修改操作
void set(K key, V value){
avl.add(key, value);
}
//查詢操作
bool contains(K key){
return avl.contains(key);
}
V get(K key){
return avl.get(key);
}
private:
AVLTree<K, V> avl;
};
#endif