zoukankan      html  css  js  c++  java
  • 数据结构与算法--跳表

    先贴上一个跳表的实现

    包括:初始化、插入、删除、搜索、整理

    这是头文件

    #pragma once
    
    #include<stdlib.h>
    #include<iostream>
    #include <math.h>
    #include<vector>//使用vector作为动态数组,便于节点的调节
    using namespace std;
    #define MAX_LEVEL 10 //最大层数
    
    template<typename T>
    class skiplist {
    private:
    	typedef struct node {
    		int key;
    		T data;
    		vector<node*> nexts;
    	}node;
    
    	int level;//层数,0是最下面,level-1是最上面
    	double num;//数据节点的数量
    	node *head;
    
    	node* createNode(int level, int key, T data) {
    		node *ns = new node;
    		ns->key = key;
    		ns->data = data;
    		for (int i = 0; i <= level; i++) {
    			ns->nexts.push_back(NULL);
    		}
    		return ns;
    	}
    	node* createHead(int level, int key) {
    		node *ns = new node;
    		ns->key = key;
    		for (int i = 0; i <= level; i++) {
    			ns->nexts.push_back(NULL);
    		}
    		return ns;
    	}
    public:
    	skiplist() {
    		num = 0;
    		level = 0;
    		head = createHead(MAX_LEVEL - 1, 0);
    		for (int i = 0; i < MAX_LEVEL; i++) {
    			head->nexts[i] = NULL;
    		}
    	}
    	//随机产生层数
    	int randomLevel() {
    		int rand_level = 1;
    		while (rand() % 2) {
    			rand_level++;
    		}
    		return (rand_level < MAX_LEVEL) ? rand_level : MAX_LEVEL;
    	}
    
    	//插入节点
    	bool insert(int key, T data) {
    		num++;
    		node *previous[MAX_LEVEL];
    		node *p, *wait_insert = NULL;
    		p = head;
    		int k = level;
    		//从最高层往下查找需要插入的位置
    		//填充previous
    		for (int i = k - 1; i >= 0; i--) {
    			while ((wait_insert = p->nexts[i]) && (wait_insert->key < key)) {
    				p = wait_insert;
    			}
    			previous[i] = p;
    		}
    		//不能插入相同的key
    		if (wait_insert&&wait_insert->key == key) {
    			return false;
    		}
    
    		//产生一个随机层数K
    		//新建一个待插入节点wait_insert
    		//一层一层插入
    		k = randomLevel();
    		//更新跳表的level
    		if (k > level) {
    			for (int i = level; i < k; i++) {
    				previous[i] = head;
    			}
    			level = k;
    		}
    		wait_insert = createNode(k, key, data);
    		//逐层更新节点的指针,和普通列表插入一样
    		for (int i = 0; i < k; i++) {
    			wait_insert->nexts[i] = previous[i]->nexts[i];
    			previous[i]->nexts[i] = wait_insert;
    		}
    		return true;
    	}
    
    	//搜索指定key的data
    	T search(int key)const {
    		node *intermediary, *target = NULL;
    		intermediary = head;
    		//从最高层开始搜
    		int k = level;
    		for (int i = k - 1; i >= 0; i--) {
    			while ((target = intermediary->nexts[i]) && (target->key <= key)) {
    				if (target->key == key) {
    					return target->data;
    				}
    				intermediary = target;
    			}
    		}
    		return NULL;
    	}
    	//删除指定key的节点
    	bool deleteSL(int key) {
    		num--;
    		node *previous[MAX_LEVEL];
    		node *p, *wait_del = NULL;
    		p = head;
    		//从最高层开始搜
    		int k = level;
    		for (int i = k - 1; i >= 0; i--) {
    			//将p调节到需要删除的节点的前一个
    			//直到wait节点的key大于等于key,之后判断若等于key则删除,大于key返回删除失败
    			while ((wait_del = p->nexts[i]) && (wait_del->key < key)) {
    				p = wait_del;
    			}
    			previous[i] = p;
    		}
    
    		//如果q是要删除的节点
    		if (wait_del&&wait_del->key == key) {
    			//就将q下一个节点的指针剪开,与previous里q之前的节点连接起来
    			for (int i = 0; i < level; i++) {
    				if (previous[i]->nexts[i] == wait_del) {
    					previous[i]->nexts[i] = wait_del->nexts[i];
    				}
    			}
    			//q没用了,删除
    			free(wait_del);
    
    			//如果删除的是最大层的节点,那么需要重新维护跳表
    			for (int i = level - 1; i >= 0; i--) {
    				if (head->nexts[i] == NULL) {
    					level--;
    				}
    			}
    			return true;
    		}//如果不等于,则返回false
    		else
    			return false;
    	}
    
    	/*重载输出运算符*/
    	friend ostream& operator<<(ostream& output, const skiplist<T>& sl) {
    		node *temp;
    		//i代表层数,该循环为层外循环
    		for (int i = sl.level - 1; i >= 0; i--) {
    			output << i << "层:" << endl;
    			//要从头开始打印
    			temp = sl.head;
    			//将每一层内的元素打印出来
    			while (temp) {
    				output << " -> " << temp->key;
    				temp = temp->nexts[i];
    			}
    			//一层打印结束,换行
    			output << "
    ";
    		}
    		//打印结束,换行
    		output << "
    ";
    		return output;
    	}
    
    	/*当链表过大,种种删除插入操作可能使得跳表索引结构不合理,此时需要重新整理结构
    	传入的两个指针应该是该区域两头的最高层节点*/
    	bool formate() {
    		node * temp = head;
    		node * next;
    		node * pre = head;
    		while (temp) {
    			node * next = temp->nexts[0];
    			temp->nexts.clear();
    			temp->nexts.push_back(next);
    			pre = temp;
    			temp = next;
    		}
    		for (int i = 0; i < level - 1; i++) {
    			pre->nexts.push_back(NULL);
    		}
    
    		int i = 0;
    		while (head->nexts[i]->nexts[i] != NULL) {
    
    			temp = head;
    
    			while (1) {
    				if (temp == NULL) {
    					break;
    				}
    				if (temp->nexts[i] == NULL) {
    					break;
    				}
    
    				if (temp->nexts[i]->nexts[i] == NULL) {
    					temp->nexts.push_back(temp->nexts[i]);
    					break;
    				}
    
    				temp->nexts.push_back(temp->nexts[i]->nexts[i]);//temp拔高一层
    				temp = temp->nexts[i]->nexts[i];
    			}
    			i++;
    		}
    		level = head->nexts.size();
    		return true;
    	}
    };
    

    这是test文件:

    #include<iostream>
    #include <string>
    #include "skiplist.h"
    using namespace std;
    
    int main() {
    	
    	cout << " 测试初始化:
    ";
    	skiplist<string> sl;
    
    	cout << " 测试插入:
    ";
    	for (int i = 1; i <= 100; i++) {
    		cout <<sl.insert(i, "hhh");
    	}
    
    	cout << " 
    测试输出运算符重载:
    ";
    	cout << endl<<sl;
    
    	cout << " 
    测试搜索功能:
    ";
    	cout << "键100的数据:" << sl.search(100) << endl;
    
    	cout << " 
    测试删除功能:
    ";
    	cout <<" 删除4号键值对:" <<sl.deleteSL(4) << endl;
    	cout << sl;
    
    	cout << " 
    测试整理功能:
    ";
    	cout<<sl.formate();
    	cout <<"
    formated:
    " <<sl;
    	system("pause");
    	return 0;
    }
    
    
    文有疏漏,请大家批评指正!
  • 相关阅读:
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit  atiMail atiDns新特性 v2  q39
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit.aticmd v4  新特性q39 添加定时器释放功能
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit. Atiposter 发帖机 新特性 poster new feature   v7 q39
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    Atitit.编程语言and 自然语言的比较and 编程语言未来的发展
    atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31
    知也atitit.解决struts2 SpringObjectFactory.getClassInstance NullPointerException  v2 q31无涯 - I
  • 原文地址:https://www.cnblogs.com/trialley/p/10541824.html
Copyright © 2011-2022 走看看