代码实现:跳表小项目

main.cpp


#include <iostream>
#include "skiplist.h"
#define FILE_PATH "./store/dumpFile"

int main() {

    // 键值中的key用int型,如果用其他类型,需要自定义比较函数
    // 而且如果修改key的类型,同时需要修改skipList.load_file函数
    SkipList<int, std::string> skipList(6);
	skipList.insert_element(1, "好好"); 
	skipList.insert_element(3, "学"); 
	skipList.insert_element(7, "习"); 
	skipList.insert_element(8, "天天"); 
	skipList.insert_element(9, "向"); 
	skipList.insert_element(19, "上"); 
	skipList.insert_element(19, "!"); 

    std::cout << "skipList size:" << skipList.size() << std::endl;

    skipList.dump_file();

    // skipList.load_file();

    skipList.search_element(9);
    skipList.search_element(18);


    skipList.display_list();

    skipList.delete_element(3);
    skipList.delete_element(7);

    std::cout << "skipList size:" << skipList.size() << std::endl;

    skipList.display_list();
}

skiplist.h

#include <iostream> 
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <mutex>
#include <fstream>

#define STORE_FILE "store/dumpFile"

std::mutex mtx;
std::string delimiter = ":";

//class template to implement node
template<typename K, typename V>
class Node{
public:
    Node(){}
    
    Node(K k, V v,int);
    
    ~Node();
    
    K get_key() const;
    
    V get_value() const;
    
    void set_value(V);

    //Linear array to hold pointers to next of different level
    Node<K,V> **forward;
    
    int node_level;
private:
    K key;
    V value;
};

template<typename K, typename V>
Node<K, V>::Node(const K k,const V v,int level){
    this->key = k;
    
    this ->value = v;
    
    this ->node_level = level;

    //level+1,因为数组的下表是从0-level
    this->forward = new Node<K,V>*[level+1];

    //把forward数组里面初始化为0
    memset(this->forward,0,sizeof(Node<K,V>*)*(level+1));

};

template<typename K, typename V>
Node<K,V>::~Node(){
    delete []forward;
};

template<typename K, typename V>
K Node<K,V>::get_key() const{
    return key;
};

template<typename K, typename V>
V Node<K,V>::get_value() const{
    return value;
};

template<typename K, typename V>
void Node<K,V>::set_value(V value){
    this->value=value ;
};


//class template for skip list
template<typename K,typename V>
class SkipList{
public:
    SkipList(int);
    ~SkipList();
    int get_random_level();
    Node<K,V>* create_note(K,V,int);
    int insert_element(K,V);
    void display_list();
    bool search_element(K);
    void delete_element(K);
    //转储
    void dump_file();
    void load_file();
    int size();

private:
    void get_key_value_from_string(const std::string& str,std::string* key,std::string* value);
    bool is_valid_string(const std::string& str);

    //maximum level of the skip list
    int _max_level;

    //current level of skip list
    int _skip_list_level;

    //pointer to header node
    Node<K,V> *_header;

    //file operator
    std::ofstream _file_writer;
    std::ifstream _file_reader;

    //skiplist current element count
    int _element_count;
};

//create new node
template<typename K,typename V>
 Node<K,V>* SkipList<K,V>::create_note(const K k,const V v,int level){
    Node<K,V> *n= new Node<K,V>(k,v,level);
    return n;
 }

// Insert given key and value in skip list 
// return 1 means element exists  
// return 0 means insert successfully
/* 
                           +------------+
                           |  insert 50 |
                           +------------+
level 4     +-->1+                                                      100
                 |
                 |                      insert +----+
level 3         1+-------->10+---------------> | 50 |          70       100
                                               |    |
                                               |    |
level 2         1          10         30       | 50 |          70       100
                                               |    |
                                               |    |
level 1         1    4     10         30       | 50 |          70       100
                                               |    |
                                               |    |
level 0         1    4   9 10         30   40  | 50 |  60      70       100
                                               +----+
*/
template<typename K, typename V>
int SkipList<K,V>::insert_element(const K key,const V value){

    mtx.lock();
    Node<K,V>* current = this->_header;

    //创建更新数组,初始化数组
    //更新数组中是node->forward[i]要放的值,也就是小于key的最大值
    Node<K,V> *update[_max_level+1];
    memset(update,0,sizeof(Node<K,V>*)*(_max_level+1));

    //从最高层开始插入跳表
    for(int i=_skip_list_level;i>=0;--i){
        while(current->forward[i] != NULL && current->forward[i]->get_key()<key){
            current = current->forward[i];
        }
        update[i]=current;
    }

    //在第0层,让forward指向右边的节点,也就是想要插入的值,即大于key的最小值
    current = current->forward[0];

    //插入的值已经存在
    if(current!=NULL && current->get_key() == key){
        std::cout<<"key: "<<key<<" ,exists"<<std::endl;
        mtx.unlock();
        return 1;
    }

    //当前节点为空时
    //当前阶段不为空时,要插入节点在update【0】和current
    if(current == NULL || current ->get_key() !=key ){

        //为节点生成一个随机的层数
        int random_level= get_random_level();

        //如果随即层数是大于跳表的目前层数,初始化大于的层数的指针为头指针
        if(random_level>_skip_list_level){
            for(int i=_skip_list_level+1;i<random_level+1;++i){
                update[i]=_header;
            }
            _skip_list_level=random_level;
        }

        // 以前面随机的层数建立一个node
        Node<K,V>* insert_node = create_note(key,value,random_level);

        // 插入节点
        for(int i=0;i<=random_level;++i){
            insert_node->forward[i]=update[i]->forward[i];
            update[i]->forward[i]=insert_node;
        }
        std::cout<< "Successfully inserted key: "<< key <<" , value: "<<value<<std::endl;
        _element_count++;
    }
    mtx.unlock();
    return 0;
}

//  显示跳表
template<typename K,typename V>
void SkipList<K,V>::display_list(){
    std::cout << "\n*****Skip List*****"<<"\n"; 
    for(int i=0;i<= _skip_list_level;++i){
        Node<K,V>*node =this->_header->forward[i];
        std::cout << "Level " << i << ": ";
        while(node!=NULL){
            std::cout<<node->get_key()<<": "<<node->get_value()<<";";
            node=node->forward[i];
        }
        std::cout << std::endl;
    }
}

// 转存数据到文件
template<typename K,typename V>
void SkipList<K,V>::dump_file(){
    
    std::cout << "dump_file-----------------" << std::endl;
    _file_writer.open(STORE_FILE);
    Node<K,V>* node=this->_header->forward[0];

    while(node!=NULL){
        _file_writer << node->get_key()<<":"<<node->get_value()<<"\n";
        std::cout<<node->get_key()<<":"<<node->get_value()<<";\n";
        node=node->forward[0];
    }

    _file_writer.flush();
    _file_writer.close();
    return ;
}

// 从磁盘加载数据
template<typename K,typename V>
void SkipList<K,V>::load_file(){

    _file_reader.open(STORE_FILE);
    std::cout << "load_file-----------------" << std::endl;
    std::string line;
    std::string* key=new std::string();
    std::string* value=new std::string();
    while(getline(_file_reader,line)){
        get_key_value_from_string(line,key,value);
        if(key->empty()|| value->empty())
            continue;
        insert_element(*key,*value);
         std::cout << "key:" << *key << "value:" << *value << std::endl;
    }
    _file_reader.close();
}

// 获取跳表的大小
template<typename K,typename V>
int SkipList<K,V>::size(){
    return _element_count;
}

template<typename K,typename V>
void SkipList<K,V>::get_key_value_from_string(const std::string& str,std::string* key,std::string* value){
    
    if(!is_valid_string(str)){
        return;
    }
    *key=str.substr(0,str.find(delimiter));
    *value =str.substr(str.find(delimiter)+1,str.length());
}

template<typename K,typename V>
bool SkipList<K,V>::is_valid_string(const std::string& str){
    if(str.empty())
        return false;
    if(str.find(delimiter)==std::string::npos)
        return false;
    return true;
}

// 从跳表中删除元素
template<typename K,typename V>
void SkipList<K,V>::delete_element(K key){

    mtx.lock();
    Node<K,V>* current = this->_header;

    //创建更新数组,初始化数组
    //更新数组中是node->forward[i]要放的值,也就是小于key的最大值
    Node<K,V> *update[_max_level+1];
    memset(update,0,sizeof(Node<K,V>*)*(_max_level+1));

    //从最高层开始遍历跳表
    for(int i=_skip_list_level;i>=0;--i){
        while(current->forward[i] != NULL && current->forward[i]->get_key()<key){
            current = current->forward[i];
        }
        update[i]=current;
    }

    //在第0层,找到想要删除值的节点
    current = current->forward[0];

    if(current!=NULL && current->get_key()==key){

        // 从最底层开始遍历,删除每一层中的值
        for(int i=0;i<=_skip_list_level;++i){
        
            // 如果这一层中没有该节点,则以上层都没有
            if(update[i]->forward[i]!=current)
                break;
        
            update[i]->forward[i]=current->forward[i];
        }

        // 移除没有使用过的层数
        while(_skip_list_level >0 &&_header->forward[_skip_list_level]==0)
            _skip_list_level--;
        
        std::cout << "Successfully deleted key "<< key << std::endl;
        _element_count--;

    }
    mtx.unlock();
}

// Search for element in skip list 
/*
                           +------------+
                           |  select 60 |
                           +------------+
level 4     +-->1+                                                      100
                 |
                 |
level 3         1+-------->10+------------------>50+           70       100
                                                   |
                                                   |
level 2         1          10         30         50|           70       100
                                                   |
                                                   |
level 1         1    4     10         30         50|           70       100
                                                   |
                                                   |
level 0         1    4   9 10         30   40    50+-->60      70       100
*/
template<typename K,typename V>
bool SkipList<K,V>::search_element(K key){

    std::cout << "search_element-----------------" << std::endl;
    Node<K,V>* current=_header;

    // 从跳表的最高层开始查找,比要求值小的最大值
    for(int i=_skip_list_level;i>=0;--i){
        while (current->forward[i] && current->forward[i]->get_key()<key){
            current =current->forward[i];
        }
    }

    // 找到 比要求值小的最大值 的下一个节点
    current = current->forward[0];

    //如果节点存在
    if(current &&current->get_key()==key){
        std::cout << "Found key: " << key << ", value: " << current->get_value() << std::endl;
        return true;
    }
    std::cout << "Not Found Key:" << key << std::endl;
    return false;
}

// 构造跳表
template<typename K,typename V>
SkipList<K,V>::SkipList(int max_level){

    this->_max_level=max_level;
    this->_skip_list_level=0;
    this->_element_count=0;

    //创建系欸但,初始化kv为空
    K k;
    V v;
    this->_header = new Node<K,V>(k,v,_max_level);
}

template<typename K,typename V>
SkipList<K,V>::~SkipList(){

    if(_file_reader.is_open())
        _file_reader.close();
    if(_file_writer.is_open())
        _file_writer.close();
    delete _header;
}

template<typename K,typename V>
int SkipList<K,V>::get_random_level(){

    int k=1;
    while(rand()%2){
        ++k;
    }
    k=(k<_max_level)?k:_max_level;
    return k;
}

在这里插入图片描述

stress_test.cpp

#include <iostream>
#include <chrono>
#include <cstdlib>
#include <pthread.h>
#include <time.h>
#include "../skiplist.h"


#define NUM_THREADS 1
#define TEST_COUNT 100000

SkipList<int,std::string> skipList(18);

void *insertElement(void* threadid){
    long tid;
    tid =(long)threadid;
    std::cout << tid << std::endl;
    int tmp=TEST_COUNT/NUM_THREADS;
    for(int i=tid*tmp,count=0;count<tmp;++i){
        ++count;
        skipList.insert_element(rand()%TEST_COUNT,"a");

    }
    pthread_exit(NULL);
}

void *getElement(void* threadid) {
    long tid; 
    tid = (long)threadid;
    std::cout << tid << std::endl;  
    int tmp = TEST_COUNT/NUM_THREADS; 
	for (int i=tid*tmp, count=0; count<tmp; i++) {
        count++;
		skipList.search_element(rand() % TEST_COUNT); 
	}
    pthread_exit(NULL);
}


int main()

{
    srand(time(NULL));
    
    pthread_t threads[NUM_THREADS];
    int rc;
    int i;

    auto start = std::chrono::high_resolution_clock::now();

    for(i =0;i <NUM_THREADS;++i){
        std::cout << "main() : creating thread, " << i << std::endl;
        rc=pthread_create(&threads[i],NULL,insertElement,(void* )i);

        if(rc){
            std::cout << "Error:unable to create thread," << rc << std::endl;
            exit(-1);
        }
    }

    void *ret;
    for(i=0;i<NUM_THREADS;++i){
        if(pthread_join(threads[i],&ret)!=0){
            perror("pthread_create() error");
            exit(3);
        }
    }
    auto finish = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double> elapsed =finish - start;
    std::cout << "insert elapsed:" << elapsed.count() << std::endl;
    pthread_exit(NULL);

        // pthread_t threads[NUM_THREADS];
        // int rc;
        // int i;
        // auto start = std::chrono::high_resolution_clock::now();

        // for( i = 0; i < NUM_THREADS; i++ ) {
        //     std::cout << "main() : creating thread, " << i << std::endl;
        //     rc = pthread_create(&threads[i], NULL, getElement, (void *)i);

        //     if (rc) {
        //         std::cout << "Error:unable to create thread," << rc << std::endl;
        //         exit(-1);
        //     }
        // }

        // void *ret;
        // for( i = 0; i < NUM_THREADS; i++ ) {
        //     if (pthread_join(threads[i], &ret) !=0 )  {
        //         perror("pthread_create() error"); 
        //         exit(3);
        //     }
        // }

        // auto finish = std::chrono::high_resolution_clock::now(); 
        // std::chrono::duration<double> elapsed = finish - start;
        // std::cout << "get elapsed:" << elapsed.count() << std::endl;
    return 0;

}

作者的测试结果
在这里插入图片描述
自己的测试结果:
插入十万条数据
在这里插入图片描述
读取十万条数据
在这里插入图片描述
待优化:
delete的时候没有释放内存。
跳表的key用int型,如果使用其他类型需要自定义比较函数,当然把这块抽象出来更好。

参考项目:https://github.com/youngyangyang04/Skiplist-CPP

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值