#include <iostream>
#include "cstdlib"
#include <cmath>
#include <cstring>
#include <mutex>
#include <fstream>
#define STORE_FILE_PATH "store/dumpFile"
std::mutex mtx;
std::string delimiter = ":";
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 v);
Node(K, V) **forward;
int node_level;
private:
K key;
V value;
};
template<typename K, typename V>
Node<K, V>::Node(K k, V v, int level) {
this->key = k;
this->value = v;
this->node_level = level;
this->forward = new Node<K,V>*[level+1];
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 v) {
this->value = v;
}
template<typename K, typename V>
class SkipList{
public:
SkipList(int);
~SkipList();
int get_random_level();
Node<K,V>* create_node(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_key(const std::string& key);
private:
int max_level;
int skip_list_level;
Node<K,V> *head_node;
int element_count;
std::ofstream _file_writer;
std::ifstream _file_reader;
};
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;
K k = NULL;
V v = NULL;
this->head_node = new Node<k, V>(k,v,max_level);
}
template<typename K, typename V>
SkipList<K, V>::~SkipList() {
if (_file_writer.is_open()) {
_file_writer.close();
}
if (_file_reader.is_open()) {
_file_reader.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;
}
template<typename K, typename V>
Node<K, V>* SkipList<K,V>::create_node(const K key, const V value, int level) {
Node<K,V> *n = new Node<K,V>(key, value, level);
return n;
}
template<typename K, typename V>
int SkipList<K, V>::insert_element(const K key, const V value) {
mtx.lock();
Node<K,V>* current = this->head_node;
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;
}
current = current->forward[0];
if (current != NULL && current->get_key() == key) {
std::cout << "key: " << key << ", exists" << std::endl;
mtx.unlock();
return 1;
}
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] = head_node;
}
skip_list_level = random_level;
}
Node<K, V>* inserted_node = create_node(key, value, random_level);
for(int i = 0; i <= random_level; i++){
inserted_node->forward[i] = update[i]->forward[i];
update[i]->forward[i] = inserted_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->head_node->forward[i];
std::cout << "Level " << i << ": ";
while (node != NULL) {
std::cout << node->get_key() << ":" << node->get_value() << "; ";
node = node->forward[i];
}
std::cout << "\n";
}
}
template<typename K, typename V>
void SkipList<K, V>::dump_file() {
std::cout << "dump_file-----------------" << std::endl;
_file_writer.open(STORE_FILE_PATH);
Node<K, V>* node = this->head_node->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_PATH);
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>
bool SkipList<K, V>::is_valid_key(const std::string &key) {
if(key.empty()){
return false;
}
if(key.find(delimiter) == std::string::npos){
return false;
}
return true;
}
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_key(str)){
return;
}
*key = str.substr(0, str.find(delimiter));
*value = str.substr(str.find(delimiter)+1);
}
template<typename K, typename V>
void SkipList<K, V>::delete_element(K key) {
mtx.lock();
Node<K, V> *current = this->head_node;
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;
}
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 && head_node->forward[skip_list_level] == 0) {
skip_list_level--;
}
std::cout << "Successfully deleted key "<< key << std::endl;
element_count--;
}
mtx.unlock();
return;
}
template<typename K, typename V>
bool SkipList<K, V>::search_element(K key) {
std::cout << "search_element-----------------" << std::endl;
Node<K, V> *current = this->head_node;
for (int i = skip_list_level; i >= 0; i--) {
while (current->forward[i] != NULL && current->forward[i]->get_key() < key) {
current = current->forward[i];
}
}
current = current->forward[0];
if (current and 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;
}
源码 from youngyangyang04/Skiplist-CPP: A tiny KV storage based on skiplist written in C++ language| 使用C++开发,基于跳表实现的轻量级键值数据库🔥🔥 🚀 (github.com)