符号表是一种通过把一个键(key)和一个值(value)联系起来,在调用时通过查找键来对键对应的值进行操作的数据结构(如c++中的map)。
符号表的主要操作有增,删,改,查四种,也可以对其进行扩展操作。下面,就对几种符号表的实现及部分扩展操作进行简要的介绍。

符号表的双数组实现

顾名思义,通过两个数组,一个存放key,一个存放value,来实现符号表。为了便于数据查找,要保证数组内数据的有序性。
这里给出完整代码:

//符号表(双数组实现版)
template<typename K,typename V>
class signTable{
	vector<K> keyV;
	vector<V> valueV;
	size_t n = 0;
public:
	signTable() = default;
	size_t size() { return n; }
	bool is_empty() { return n == 0; }
	K max() { return is_empty() ? NULL : keyV[n - 1]; }
	K min() { return is_empty() ? NULL : keyV[0]; }
	K select(size_t r) { return (r < n) ? keyV[r] : NULL; }
	size_t rank(K key);
	size_t rank(K lo, K hi);
	void insert(K key, V value);
	V get(K key);
	void dele(K key);
	K ceiling(K key);
	K floor(K key);
	vector<K> cut_key(K lo, K hi);
};
template<typename K, typename V>
size_t signTable<K, V>::rank(K key) {
	if (is_empty()) { return 0; }
	int lo = 0, hi = n - 1, mid;
	while (lo <= hi) {
		mid = lo + (hi - lo) / 2;
		if (key < keyV[mid]) { hi = mid - 1; }
		else if (key > keyV[mid]) { lo = mid + 1; }
		else { return mid; }
	}
	return lo;
}
template<typename K, typename V>
size_t signTable<K, V>::rank(K lo,K hi) {
	if (hi <= lo) { return 0; }
	else { return rank(hi) - rank(lo); }
}
template<typename K, typename V>
void signTable<K, V>::insert(K key, V value) {
	size_t temp = rank(key);
	if (temp == n) {
		keyV.push_back(key);
		valueV.push_back(value);
		++n;
	}
	else if (keyV[temp] == key) { valueV[temp] = value; }
	else {
		keyV.push_back(keyV[n - 1]);
		valueV.push_back(valueV[n - 1]);
		for (int i = n - 1; i > temp; --i) {
			keyV[i] = keyV[i - 1];
			valueV[i] = valueV[i - 1];
		}
		keyV[temp] = key;
		valueV[temp] = value;
		++n;
	}
}
template<typename K, typename V>
V signTable<K, V>::get(K key) {
	size_t temp = rank(key);
	if (temp == n || keyV[temp] != key) { return NULL; }
	return valueV[temp];
}
template<typename K, typename V>
void signTable<K, V>::dele(K key) {
	size_t temp = rank(key);
	if (temp == n || keyV[temp] != key) { return; }
	while (temp < n - 1) {
		valueV[temp] = valueV[temp + 1];
		keyV[temp] = keyV[++temp];
	}
	valueV.pop_back();
	keyV.pop_back();
	--n;
}
template<typename K, typename V>
K signTable<K, V>::ceiling(K key) {
	size_t temp = rank(key);
	if (temp == n) { return NULL; }
	return keyV[temp];
}
template<typename K, typename V>
K signTable<K, V>::floor(K key) {
	size_t temp = rank(key);
	if (temp == 0 && keyV[temp] != key) { return NULL; }
	if (temp == n || keyV[temp] != key) { return keyV[temp - 1]; }
	return key; 
}
template<typename K, typename V>
vector<K> signTable<K, V>::cut_key(K lo, K hi) {
	vector<K> temp;
	K temp1 = ceiling(lo);
	if (!temp1) { return temp; }
	size_t temp2 = rank(floor(hi));
	for (size_t i = rank(temp1); i <= temp2; ++i) {
		temp.push_back(keyV[i]);
	}
	return temp;
}

函数详细解释:

  1. rank(K key) :使用二分查找,找出所提供的key在表中的秩,如果表中没有key,则返回大于key的最小值(如果不存在则是表尾)的秩。
  2. rank(K lo, K hi) :两个key的秩的差值。
  3. insert(K key, V value) :插入和修改操作,如果key已存在,则修改value(表中key具有唯一性);key不存在则插入,在插入时仍保证表的有序性。
  4. get(K key) :查找操作,返回key对应的value,如果key不存在则返回NULL。
  5. dele(K key) :删除操作,删除后仍保证表的有序性。
  6. ceiling(K key) :天花板,返回大于等于key的最小值的秩(不存在返回Null)。
  7. floor(K key) :地板,返回小于等于key的最大值的秩(不存在返回Null)。
  8. cut_key(K lo, K hi) :切片,返回一个由大于等于lo小于等于hi的秩组成的vector。

rank通过二分查找来获取秩,而几乎所有操作都是通过rank提供的秩来实现的,这也保证了程序的高效性。双数组符号表的查找性能可以达到O(lgN)级别,但它的插入操作仍是O(N)级别。

符号表的二叉搜索树实现

用二叉树实现的符号表,每个节点存放key,value,n(以它为根节点的树的节点数)和指向左右树的智能指针(防止内存泄漏)。通过递归,自顶向下地进行查找,保证较低的时间复杂度。

这里给出完整代码:

//符号表(二叉搜索树实现版)
class BST {	
	struct Node {
		int key;
		int value;
		shared_ptr<Node> left, right;
		int n;
		Node(int key, int value, int n) :key(key), value(value), n(n) {}
	};
	shared_ptr<Node>root;
	int size(shared_ptr<Node> node) { return node ? node->n : 0; }
	int get(shared_ptr<Node> node, int key) {
		if (node == nullptr) { return 0; }
		if (key < node->key) { return get(node->left, key); }
		else if (key > node->key) { return get(node->right, key); }
		else { return node->value; }
	}
	shared_ptr<Node> put(int key, int value, shared_ptr<Node> node) {
		if (node == nullptr) { node = shared_ptr<Node>(new Node(key, value, 1)); }
		else if (key < node->key) { node->left = put(key, value, node->left); }
		else if (key > node->key) { node->right = put(key, value, node->right); }
		else { node->value = value; }
		node->n = size(node->left) + size(node->right) + 1;
		return node;
	}
	shared_ptr<Node> max(shared_ptr<Node> node) {
		if (node->right == nullptr) { return node; }
		else { return max(node->right); }
	}
	shared_ptr<Node> min(shared_ptr<Node> node) {
		if (node->left == nullptr) { return node; }
		else { return min(node->left); }
	}
	shared_ptr<Node> floor(int key, shared_ptr<Node> node) {
		if (node == nullptr) { return node; };
		if (key < node->key) { return floor(key, node->left); }
		else if (key == node->key) { return node; }
		shared_ptr<Node> tem = floor(key,node->right);
		if (tem) { return tem; }
		return node;
	}
	shared_ptr<Node> ceiling(int key, shared_ptr<Node> node) {
		if (node == nullptr) { return node; };
		if (key > node->key) { return floor(key, node->right); }
		else if (key == node->key) { return node; }
		shared_ptr<Node> tem = floor(key, node->left);
		if (tem) { return tem; }
		return node;
	}
	shared_ptr<Node> select(int ran, shared_ptr<Node> node) {
		if (node == nullptr) { return NULL; }
		int t = size(node->left);
		if (ran < t) { return select(ran, node->left); }
		else if (ran > t) { return select(ran - t - 1, node->left); }
		else { return node; }
	}
	int rank(int key, shared_ptr<Node> node) {
		if (node == nullptr) { return NULL; }
		if (key < node->key) { return rank(key, node->left); }
		else if (key > node->key) { return size(node->left) + 1 + rank(key, node->right); }
		else { return size(node->left); }
	}
	shared_ptr<Node> deleteMax(shared_ptr<Node> node) {
		if (node->right == nullptr) { return node->left; }
		node->right = deleteMax(node->right);
		node->n = size(node->left) + 1 + size(node->right);
		return node;
	}
	shared_ptr<Node> deleteMin(shared_ptr<Node> node) {
		if (node->left == nullptr) { return node->right; }
		node->left = deleteMin(node->left);
		node->n = size(node->left) + 1 + size(node->right);
		return node;
	}
	shared_ptr<Node> deleteKey(shared_ptr<Node> node,int key) {
		if (node == nullptr) { return nullptr; }
		if (key < node->key) { node->left = deleteKey(node->left, key); }
		else if (key > node->key) { node->right = deleteKey(node->right, key); }
		else {
			if (node->left == nullptr) { return node->right; }
			if (node->right == nullptr) { return node->left; }
			shared_ptr<Node>tem = min(node->right);
			node->key = tem->key;
			node->value = tem->value;
			node->right = deleteMin(node->right);
		}
		node->n = size(node->left) + 1 + size(node->right);
		return node;
	}
	vector<int>& keys(shared_ptr<Node>node, vector<int>& vk, int l, int r) {
		if (node == nullptr) { return vk; }
		if (l < node->key) { vk = keys(node->left, vk, l, r); }
		if (l <= node->key && r >= node->key) { vk.push_back(node->key); }
		if (r > node->key) { vk = keys(node->right, vk, l, r); }
		return vk;
	}
public:
	int size() { return size(root); }
	int get(int key) { return get(root, key); }
	void put(int key, int value) { root = put(key, value, root); }
	int max() { return max(root)->key; }
	int min() { return min(root)->key; }
	

相关文章:

  • 2021-05-15
  • 2021-10-03
  • 2021-08-19
  • 2021-12-13
  • 2021-11-20
  • 2021-08-02
  • 2022-12-23
猜你喜欢
  • 2021-07-25
  • 2021-12-07
  • 2021-08-09
  • 2021-12-09
  • 2022-01-24
  • 2022-12-23
  • 2022-01-15
相关资源
相似解决方案