瀏覽代碼

完成skiplist的输入逻辑,还没有经过测试

Gogs 4 月之前
父節點
當前提交
5e2a7824b7
共有 6 個文件被更改,包括 269 次插入0 次删除
  1. 6 0
      .gitignore
  2. 9 0
      CMakeLists.txt
  3. 14 0
      STL/basical/type_checking.h
  4. 227 0
      STL/extend/skiplist.h
  5. 0 0
      main_test.cpp
  6. 13 0
      test.cpp

+ 6 - 0
.gitignore

@@ -28,3 +28,9 @@
 *.out
 *.app
 
+
+build/
+.vscode/
+test
+
+

+ 9 - 0
CMakeLists.txt

@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.15)
+project(nanxing_stl VERSION 1.0)
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
+
+
+
+
+add_executable(MAIN_TEST main_test.cpp)

+ 14 - 0
STL/basical/type_checking.h

@@ -0,0 +1,14 @@
+//用偏特化检验特型能否满足一些条件
+#include<type_traits>
+namespace nanxing_extend
+{
+    template<typename V>
+    using void_t=void;
+
+    template<typename T,typename V=void>
+    struct compare_admit:std::false_type{};
+
+
+    template<typename T>
+    struct compare_admit<T,void_t<decltype(std::declval<T>()<std::declval<T>())>>:std::true_type{};
+}

+ 227 - 0
STL/extend/skiplist.h

@@ -0,0 +1,227 @@
+#include"basical/type_checking.h"
+#include<cstdlib>
+#include<cstring> 
+#include<exception>
+#include<random>
+namespace nanxing_extend
+{
+    //错误处理机制
+    class nextpoint_new:std::exception             //skip_node分配空间失败的时候
+    {
+        const char* what() const noexcept
+        {
+            return "malloc next_node point fault";
+        }
+    };
+
+    
+    class newNode_error:std::exception             //申请新的空间的时候
+    {
+        const char* what() const noexcept
+        {
+            return "malloc new node error";
+        }
+    };
+    class random_error:std::exception             //申请预设随机数空间的时候
+    {
+        const char* what() const noexcept
+        {
+            return "malloc random space error";
+        }
+    };
+
+    
+    
+    enum class Skip_result          //跳表操作的结果           
+    {
+        successufl,
+        fault,
+        full
+    };
+    template<typename V>
+    union skiplistre
+    {
+        V value,
+        Skip_result result
+    };
+    
+
+    //注意这里的V只能是要么是能直接深拷贝的类型,要么是指向堆上数据的指针类型
+    template<typename K,typename V>
+    struct skip_node
+    {
+        static_assert(nanxing_extend::compare_admit<K>value);
+        static_assert(nanxing_extend::compare_admit<V>value);
+        skip_node<K,V>** next_node; 
+        V value;
+    private:
+        K key;
+        int level;
+        
+    public:
+        
+        skip_node(){};
+        skip_node(K _key,V _value,int _level):key(_key),value(_value),level(_level){};
+        init_next(int level)
+        {
+            try
+            {
+                next_node=::new (skip_node<K,V>*)[level];
+            }
+            catch(std::bad_alloc){        //捕获内存分配错误
+                throw nextpoint_new();       //重新抛出一个定制的更详细的类型用以明确错误的具体位置
+            }
+            std::memset(next_node,0,sizeof(skip_node<K,V>*)*level);
+        }
+        K get_key(){ return key; }
+    };
+
+
+    template<typename K,typename V>
+    class skipList
+    {
+        static_assert(nanxing_extend::compare_admit<K>value);
+        static_assert(nanxing_extend::compare_admit<V>value);
+    private:
+        using Node=skip_node<K,V>;
+        using Nptr=Node**;
+        //由于C++的便利性我们考虑使用带头节点的跳表(C++允许对数据不进行初始化(默认构造函数))
+        Nptr head;                      //头节点
+        int max_level;                 //最大高度
+        int* random_level;
+        int current_level;              //跳表当前高度
+        int current_size;               //跳表当前尺寸
+        //这里出于一个考虑,当跳表单纯作为小数据内存数据库,单表大小限制是没有意义的
+        //但是像level_db这样作为KV数据库的缓存的时候,就需要限制大小进行落盘
+
+        #ifdef SKIP_MAX_SIZE
+        int max_size;                   //跳表允许的最大尺寸
+        #endif
+    public:
+        #ifndef SKIP_MAX_SIZE
+        skipList(int _max_level):max_level(_max_level),random_level(nullptr)
+        {
+            try
+            {
+                Node* middle=::new skip_node;
+                middle->init_next(max_level);
+                head=::new (Node*)[max_level];
+                for(auto& i in head)                
+                {
+                    i=middle;
+                }
+            }
+            catch(std::bad_alloc)
+            {
+                throw newNode_error();
+            }
+        }
+        #elif
+        skipList(int _max_level,int _max_size):max_size(_max_size),max_level(_max_level),random_level(nullptr)
+        {
+            try
+            {
+                Node* middle=::new skip_node;
+                middle->init_next(max_level);
+                head=::new (Node*)[max_level];
+                for(auto& i in head)                
+                {
+                    i=middle;
+                }
+            }
+            catch(std::bad_alloc)
+            {
+                throw newNode_error();
+            }
+        }
+        #endif
+        [[nodiscard]]                            //这个返回值最好不要忽略否则很有可能会出现内存泄漏
+        skiplistre<V> insert(K _key,V _value)              //如果相同的时候我们考虑将value返回因为value很可能会是一个指针,需要手动清空内存
+        {
+            using ptr=Node*;
+            int rand_level=0;
+            ptr updata[max_level]={nullptr};          //用于更新的数组
+            int level=current_level-1;
+            ptr point=head[level];
+            skiplistre<V> sk;
+            ptr new_node;
+
+            for(int i=level;i>=0;i--)
+            {
+                for(;;)
+                {
+                    if(point->next_node[level]==nullptr)
+                    {
+                        updata[level]=point;
+                        break;
+                    }
+                    else if(point->next_node[level]->key>=_key)
+                    {
+                        if(point->next_node[level]->key==_key)
+                        {
+                            
+                            sk.value=std::move(point->next_node[level]->value);          //这个值已经不需要了,直接移动
+                            point->next_node[level]->value=_value;
+                            return sk;
+                        }
+                        else
+                        {
+                            updata[level]=point;
+                            break;
+                        }
+                        else{
+                            point=point->head[level];              //更新point指针
+                        }
+                    }
+                }
+                [[likely]]
+                if(random_level!=nullptr)
+                {
+                    rand_level=random_level[current_size%1024];
+                    new_node=new skip_node(_key,_value,rand_level);
+                }
+                [[unlikely]]
+                else
+                {
+                    rand_level=std::rand(chrono::system_clock::now().time_since_epoch().count())%(1+max_level);
+                    new_node=new skip_node(_key,_value,rand_level);
+                }
+                ptr tmp=nullptr;
+                for(int i=0;i<=level;i++)
+                {
+                    tmp=updata[i]->next_node[i];
+                    updata[i]->next_node[i]=new_node;
+                    new_node->next_node[i]=tmp;
+                }
+            }
+            sk.Skip_result=Skip_result::successufl;
+        }
+        
+        skiplistre<V> search(K _key)
+        {
+
+        }
+
+
+        void init_skip()                 //直接生成随机数表
+        {
+            try{
+                random_level=new int[1024];                     //刚好是一页的大小(4KB)
+            }
+            catch(std::bad_alloc)
+            {
+                throw random_error();
+            }
+            std::mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
+            for(auto& i :random_level)
+            {
+                i=(rnd()%max_level)+1;
+            }
+
+        }
+    };
+
+    
+}
+
+

+ 0 - 0
main_test.cpp


+ 13 - 0
test.cpp

@@ -0,0 +1,13 @@
+#include<iostream>
+int main()
+{
+    int a[10]={0};
+    for(auto& i : a)
+    {
+        i=1;
+    }
+    for(auto j :a)
+    {
+        std::cout<<j<<std::endl;
+    }
+}