C++ 数据结构学习 ---- 跳转表

目录

1. 头文件

1.1 词典头文件

1.2 词条头文件

1.3 列表头文件

1.4 四链表头文件

1.5 四链表节点头文件

1.6 跳转表头文件

2. 相关函数

2.1 查找函数

2.2 删除函数

2.3 插入函数

3. 完整代码

4. 运行结果及截图


1. 头文件

1.1 词典头文件


template <typename K, typename V> struct Dictionary { //词典Dictionary模板类
	virtual int size() const = 0; //当前词条总数
	virtual bool put(K, V) = 0; //插入词条(禁止雷同词条时可能失败)
	virtual V* get(K k) = 0; //读取词条
	virtual bool remove(K k) = 0; //删除词条
};

1.2 词条头文件

//词条模板类
template <typename K, typename V> struct Entry { 
	K key; V value; //关键码、数值
	Entry(K k = K(), V v = V()) : key(k), value(v) {}; //默认构造函数
	Entry(Entry<K, V> const& e) : key(e.key), value(e.value) {}; //基于克隆的构造函数
	bool operator< (Entry<K, V> const& e) { return key < e.key; }  //比较器:小于
	bool operator> (Entry<K, V> const& e) { return key > e.key; }  //比较器:大于
	bool operator== (Entry<K, V> const& e) { return key == e.key; } //判等器:等于
	bool operator!= (Entry<K, V> const& e) { return key != e.key; } //判等器:不等于
}; //得益于比较器和判等器,从此往后,不必严格区分词条及其对应的关键码

1.3 列表头文件

请点击

C++ 数据结构学习 ---- 列表_孤城寻欢的博客-CSDN博客_c++列表

1.4 四链表头文件

#include "QuadListNode.h" //引入Quadlist节点类

template <typename T> struct Quadlist { //四联列表
	int _size; //规模
	QNodePosi<T> header, trailer; //头哨兵、尾哨兵
	void init(); //初始化
	int clear(); //清除所有节点
	Quadlist() { init(); } //构造
	~Quadlist() { clear(); delete header; delete trailer; } //析构
	T remove(QNodePosi<T> p); //删除(合法)位置p处的节点,返回被删除节点的数值
	QNodePosi<T> insert(T const& e, QNodePosi<T> p, QNodePosi<T> b = NULL); //将e作为p的后继、b的上邻插入
	void traverse(void (*) (T&)); //遍历各节点,依次实施指定操作(函数指针,只读或局部修改)
	template <typename VST> void traverse(VST&); //遍历
}; //Quadlist

 //Quadlist初始化,创建Quadlist对象时统一调用
template <typename T> void Quadlist<T>::init() {
	header = new QNode<T>; //创建头哨兵节点
	trailer = new QNode<T>; //创建尾哨兵节点
	header->succ = trailer; header->pred = NULL; //沿横向联接哨兵
	trailer->pred = header; trailer->succ = NULL; //沿横向联接哨兵
	header->above = trailer->above = NULL; //纵向的后继置空
	header->below = trailer->below = NULL; //纵向的前驱置空
	_size = 0; //记录规模
} //如此构造的四联表,不含任何实质的节点,且暂时与其它四联表相互独立


//将e作为p的后继、b的上邻插入Quadlist
template <typename T> QNodePosi<T> 
	Quadlist<T>::insert(T const& e, QNodePosi<T> p, QNodePosi<T> b)
	{
		_size++; return p->insert(e, b);
	} //返回新节点位置(below = NULL)


//删除Quadlist内位置p处的节点,返回其中存放的词条
template <typename T> 
	T Quadlist<T>::remove(QNodePosi<T> p) { //assert: p为Quadlist中的合法位置
		p->pred->succ = p->succ; p->succ->pred = p->pred; _size--;//摘除节点
		T e = p->entry; delete p; //备份词条,释放节点
		return e; //返回词条
	}
 //清空Quadlist
template <typename T> int Quadlist<T>::clear() {
		int oldSize = _size;
		while (0 < _size) remove(header->succ); //逐个删除所有节点
		return oldSize;
}
//遍历Quadlist,对各节点依次实施visit操作
template <typename T> void Quadlist<T>::traverse(void (*visit) (T&)) { //利用函数指针机制,只读或局部性修改
	QNodePosi<T> p = header;
	while ((p = p->succ) != trailer) visit(p->data);
}
//遍历Quadlist,对各节点依次实施visit操作
template <typename T> template <typename VST> void Quadlist<T>::traverse(VST& visit) { //利用函数对象机制,可全局性修改
	QNodePosi<T> p = header;
	while ((p = p->succ) != trailer) visit(p->data);
}
 //将e作为当前节点的后继、b的上邻插入Quadlist
template <typename T> QNodePosi<T> QNode<T>::insert(T const& e, QNodePosi<T> b) {
		QNodePosi<T> x = new QNode<T>(e, this, succ, NULL, b); //创建新节点
		succ->pred = x; succ = x; //设置水平逆向链接
		if (b) b->above = x; //设置垂直逆向链接
		return x; //返回新节点的位置
	}

1.5 四链表节点头文件

#include "Entry.h"

template <typename T> struct QNode;
template <typename T> using QNodePosi = QNode<T>*; //跳转表节点位置
template <typename T> struct QNode { //四联节点
    T entry; //所存词条
    QNodePosi<T> pred, succ, above, below; //前驱、后继、上邻、下邻
    QNode(T e = T(), QNodePosi<T> p = NULL, QNodePosi<T> s = NULL,
        QNodePosi<T> a = NULL, QNodePosi<T> b = NULL) //构造器
        : entry(e), pred(p), succ(s), above(a), below(b) {}
    QNodePosi<T> insert(T const& e, QNodePosi<T> b = NULL); //将e作为当前节点的后继、b的上邻插入
};

1.6 跳转表头文件

#include "Dictionary.h"//引入词典
#include "Entry.h"//引入词条
#include "List.h"//引入列表
#include "Quadlist .h"//引入四联表

template <typename K, typename V> //key、value
//符合Dictionary接口的Skiplist模板类(隐含假设元素之间可比较大小)
struct Skiplist : public Dictionary<K, V>, public List< Quadlist< Entry<K, V> >* > {
	Skiplist() { this->insertAsFirst(new Quadlist< Entry<K, V> >); }; //即便为空,也有一层空列表
	QNodePosi< Entry<K, V> > search(K); //由关键码查询词条
	int size() const { return this->empty() ? 0 : this->last()->data->_size; } //词条总数
	int height() { return this->size(); } //层高 == #Quadlist
	V* get(K); //读取
	bool put(K, V); //插入(Skiplist允许词条重复,故必然成功)
	bool remove(K); //删除
};

2. 相关函数

2.1 查找函数

//跳转表词条查找算法
template <typename K, typename V> V* Skiplist<K, V>::get(K k) { 
	QNode< Entry<K, V> >* p = search(k); //无论是否命中,search()都不会返回NULL
	return (p->pred && p->entry.key == k) ? &(p->entry.value) : NULL; //故须再做判断
} //有多个命中时靠后者优先

2.2 删除函数


//跳转表词条删除算法
template <typename K, typename V> bool Skiplist<K, V>::remove(K k) { 
	QNodePosi< Entry<K, V> > p = search(k); //查找目标词条
	if (!p->pred || (k != p->entry.key))  return false; //若不存在,直接返回
	ListNodePosi< Quadlist< Entry<K, V> >* > qlist = this->last(); //从底层Quadlist开始
	while (p->above) { qlist = qlist->pred; p = p->above; } //升至塔顶
	do { //逐层拆塔
		QNodePosi< Entry<K, V> > lower = p->below; //记住下一层节点,并
		qlist->data->remove(p); //删除当前层节点,再
		p = lower; qlist = qlist->succ; //转入下一层
	} while (qlist->succ); //直到塔基
	while ((1 < height()) && (this->first()->data->_size < 1)) { //逐层清除

		
	//List<K>::remove(this->first());
		this->first()->data->header->above = NULL;
	} //已不含词条的Quadlist(至少保留最底层空表)
	return true; //删除成功
} //体会:得益于哨兵的设置,哪些环节被简化了? 



/******************************************************************************************
 * Skiplist词条查找算法(供内部调用)
 * 返回关键码不大于k的最后一个词条(所对应塔的基座)
 ******************************************************************************************/


template <typename K, typename V> QNodePosi< Entry<K, V> > Skiplist<K, V>::search(K k) {
	for (QNodePosi< Entry<K, V> > p = this->first()->data->header; ; ) //从顶层Quadlist的首节点p出发
		if ((p->succ->succ) && (p->succ->entry.key <= k)) { p = p->succ; } //尽可能右移
		else if (p->below) { p = p->below; } //水平越界时,下移
		else  return p; //验证:此时的p符合输出约定(可能是最底层列表的header)
} //体会:得益于哨兵的设置,哪些环节被简化了?

2.3 插入函数

 //跳转表词条插入算法
template <typename K, typename V> bool Skiplist<K, V>::put(K k, V v) {
	Entry<K, V> e = Entry<K, V>(k, v); //待插入的词条(将被同一塔中所有节点共用)
	QNodePosi< Entry<K, V> > p = search(k); //查找插入位置:新塔将紧邻其右,逐层生长
	ListNodePosi< Quadlist< Entry<K, V> >* > qlist = this->last(); //首先在最底层
	QNodePosi< Entry<K, V> > b = qlist->data->insert(e, p); //创建新塔的基座
	while (rand() & 1) { //经投掷硬币,若确定新塔需要再长高,则
		while (p->pred && !p->above) p = p->pred; //找出不低于此高度的最近前驱
		if (!p->pred && !p->above) { //若该前驱是header,且已是最顶层,则
			this->insertAsFirst(new Quadlist< Entry<K, V> >); //需要创建新的一层
			this->first()->data->header->below = qlist->data->header;
			qlist->data->header->above = this->first()->data->header;
		}
		p = p->above; qlist = qlist->pred; //上升一层,并在该层
		b = qlist->data->insert(e, p, b); //将新节点插入p之后、b之上
	} //课后:调整随机参数,观察总体层高的相应变化
	return true; //Dictionary允许重复元素,插入必成功
} //体会:得益于哨兵的设置,哪些环节被简化了?

3. 完整代码

#include<iostream>
#include <ctime>
#include "Dice.h"

using namespace std;

 // 测试跳转表
template <typename K, typename V> void testSkiplist(int n) {
    Skiplist<K, V> L;
    while (L.size() < n)
        switch (dice(3)) {
        case 0: { //查找,成功率 <= 33.3%
            K key = dice((K)n * 3); //[0, 3n)范围内的key
            cout << "搜索:" << key << "..." << endl;
        
            V* pValue = L.get(key);
            if(pValue)
            cout << "找到了:" << (*pValue) << endl;
            else
                cout << "没有找到!" << endl;
            break;
        }
        case 1: { //删除,成功率 <= 33.3%
            K key = dice((K)n * 3); //[0, 3n)范围内的key
            cout << "删除:" << key << "...";
           // printf("Removing "); print(key); printf(" ... ");
            if (L.remove(key)) {
                cout << "删除成功!" << endl; //printf("Done\n"); print(L);
            }
            else
                cout << "词条不存在!" << endl;//printf("Entry not exists\n\n");
            break;
        }
        default: {//插入,成功率 == 100%
            K k = dice((K)n * 3); V v = (V)'A' + dice(26); //在[0, 2n)*['A'~'Z']范围内的词条
            cout << "插入:<" << k << "," << v << ">...";
            //printf("Inserting <"); print(k); printf(","); print(v); printf("> ... ");
            L.put(k, v);
            cout << "插入成功!" <<endl;//printf("Done\n");print(L);
            break;
        }
        }
    while (L.size() > 0) {
        K key = dice((K)n * 3); //[0, 3n)范围内的key
        cout << "删除:" << key << "...";// printf("Removing "); print(key); printf(" ... ");
        if (L.remove(key))
            cout << "删除完成!" << endl;
        else
            cout << "词条不存在!" << endl;
      //  L.remove(key) ? printf("Done\n") : printf("Entry not exists\n");
     //   print(L); printf("\n");
    }
}

int main() {
    testSkiplist<int, char>(5); //元素类型可以在这里任意选择
    system("pause");
    return 0;
}

4. 运行结果及截图

  以上所有代码参考邓俊辉老师的《c++语言版数据结构》!

猜你喜欢

转载自blog.csdn.net/qq_58240448/article/details/128115199