符号表是一张抽象的表格, 将信息存储到里面, 可以按指定的键来搜索获取这些信息,且键不能重复。 例如:数据库。
编译器可以用符号表来根据变量名来找到对应的值和类型。
无序链表的符号表:
用链表实现的符号表
符号表的API为
void put(KEY k, VAL v); //插入值
VAL get(KEY k); //得到对应键的值
void delete(KEY k); //删除键为k的键和值
bool contains(KEY k); //表中是否包含键k
bool is_empty(KEY k); //表是否为空
int size(); //表中的元素数
KEY max(); //最大的键
KEY min(); //最小的键
其中插入操作比较特殊
先遍历链表, 查找表中是否已经存在键k, 若存在,则改变键k的val值, val = v; 若不存在, 新建一个节点插入到表头。
void put(KEY k, VAL v){
for(node<KEY, VAL> *t = first; t != NULL; t = t->next)
if(t->key == k){t->val = v; return;}
first = new node<KEY, VAL>(k, v, first);
}
完整的代码实现如下:
#include<iostream>
using namespace std;
template <class KEY, class VAL>
class node{
public:
KEY key;
VAL val;
node<KEY, VAL> *next;
node<KEY, VAL> (){key = NULL; val = NULL; next = NULL;}
node<KEY, VAL>(KEY k, VAL v, node<KEY, VAL> *n){key = k; val = v; next = n;}
};
template <class KEY, class VAL>
class Seq_search_ST{
node<KEY, VAL> *first;
public:
Seq_search_ST(){first = new node<KEY, VAL>(); first = NULL;}
void put(KEY k, VAL v){
for(node<KEY, VAL> *t = first; t != NULL; t = t->next)
if(t->key == k) {t->val = v; return;}
first = new node<KEY, VAL>(k, v, first);
}
VAL get(KEY k){
for(node<KEY, VAL> *t = first; t != NULL; t = t->next)
if(t->key == k) return t->val;
return NULL;
}
void del(KEY k){
if(first->key == k){first = first->next; return;}
for(node<KEY, VAL> *t = first; t != NULL; t = t->next)
if(t->next->key == k){t ->next = t->next->next; return;}
cout << "key is not exist\n";
}
bool contains(KEY k){
for(node<KEY, VAL> *t = first; t != NULL; t = t->next)
if(t->key == k) return true;
return false;
}
bool is_empty(){return first->key == NULL;}
int size(){
int cnt = 0;
for(node<KEY, VAL> *t = first; t != NULL; t = t->next) cnt++;
return cnt;
}
KEY Min(){
VAL min_val = first->val;
KEY min_key = first->key;
for(node<KEY, VAL> *t = first->next; t != NULL; t = t->next)
if(t->val < min_val) {min_val = t->val; min_key = t->key;}
return min_key;
}
KEY Max(){
VAL max_val = first->val;
KEY max_key = first->key;
for(node<KEY, VAL> *t = first->next; t != NULL; t = t->next)
if(t->val > max_val) {max_val = t->val; max_key = t->key;}
return max_key;
}
};
int main(){
Seq_search_ST<int, double> st;
st.put(1,4);
st.put(2,5);
cout << st.Min();
return 0;
}
有序数组的符号表
因为用链表实现, 插入和删除操作很慢, 所以有了用有序数组存储的符号表, 基于二分查找。
核心操作为
int rank(KEY k){
int lo = 0, hi = N - 1;
while(lo <= hi){
int mid = lo + (hi - lo) / 2;
if(keys[mid] < k) lo = mid + 1;
else if(keys[mid] > k) hi = mid - 1;
else return mid;
}
return lo;
}
该函数可返回小于键k的个数。
插入操作:
先调用rank函数, 判断表中是否已经存在键k, 若存在, 则更新键k的val, 若不存在, 把rank的返回值后面的数值中的值都往后移一位, 然后插入。
删除操作:
调用rank函数, 返回其键k的位置, 删除, 若不存在键k, 直接返回。
#include<iostream>
using namespace std;
template <class KEY, class VAL>
class Binary_search_ST{
KEY *keys;
VAL *vals;
int N;
public:
Binary_search_ST(int capacity){keys = new KEY[capacity]; vals = new VAL[capacity]; N = 0;}
int rank(KEY k){
int lo = 0, hi = N-1;
while(lo <= hi){
int mid = lo + (hi - lo) / 2;
if(keys[mid] < k) lo = mid + 1;
else if(keys[mid] > k) hi = mid - 1;
else return mid;
}
return lo;
}
void put(KEY k, VAL v){
int i = rank(k);
if(i < N && keys[i] == k){vals[i] = v; return;}
for(int j = N; j > i; --j){keys[j] = keys[j-1]; vals[j] = vals[j-1];}
keys[i] = k; vals[i] = v;
N++;
}
VAL get(KEY k){
if(N == 0) return NULL;
int i = rank(k);
if(i < N && keys[i] == k) return vals[i];
return NULL;
}
void del(KEY k){
int i = rank(k);
if(i < N && keys[i] == k){
if(i == N-1) {N--; return;}
for(int j = N - 1; j > i; --j){
keys[j-1] = keys[j];
vals[j-1] = vals[j];
}
N--;
}
else cout << "key is not exist\n";
}
bool contains(KEY k){
int i = rank(k);
if(i < N && keys[i] == k) return true;
return false;
}
KEY min(){
return keys[0];
}
KEY max(){
return keys[N-1];
}
KEY ceiling(KEY k){
int i = rank(k);
}
};
int main(){
Binary_search_ST<int, double> st(10);
st.put(1, 2);
st.put(2, 3);
//st.del(2);
if(st.contains(2))
cout << "yes\n";
return 0;
}