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;
    }
    
    
    文有疏漏,请大家批评指正!
  • 相关阅读:
    vb移动窗体的代码
    vb得到一个进程的启动参数?
    UTF8方式读写文件的模块
    JavaScript中Window.event详解
    vb设置窗体不可移动
    一拖二
    实习第一天
    사랑해
    决定考研
    Eclipse快捷键
  • 原文地址:https://www.cnblogs.com/trialley/p/10541824.html
Copyright © 2011-2022 走看看