跳表c++实现

    科技2024-12-13  13

    原理:https://blog.csdn.net/u013011841/article/details/39158585

    一.跳表结构

    一种插入、查询、删除时间效率为O(log n)空间效率为O(n)的数据结构,效率堪比红黑树,但是实现起来更加简易,内存空间使用更小,便于调试。

    1.节点

    //节点 class node { int val; int level;//节点的高度(层次) node* forword[MAXLEVEL];//指向node*的数组 };

    2.skiplist(管理整个表的一个数据结构)

    class skiplist { private: node* head;//指向跳表的头结点 int max_length;//计算跳表的最大节点个数 }

    随机生成level算法

    //随机生成level算法 int randomLevel() { int k = 1; while (rand() % 2) { k++; } k = (k < MAXLEVEL) ? k : MAXLEVEL; return k; }

    二、具体实现

    class node { public: node(int val,int level) { this->val = val; this->level = level; //初始化节点指针 //forword = (node**)malloc(sizeof(node*) * level); for (int i = 0; i < MAXLEVEL; i++) { forword[i] = NULL; } } ~node() { } int val; int level; node* forword[MAXLEVEL];//指向node*的数组 }; class skiplist { public: skiplist() { //head = NULL; max_length = 0; //初始化head为一个5层的val(0)的node node* p = new node(0, 5); head = p; } //注:所有方法都是跳过第一个节点(5层的val(0)), void insert(int val) { int level = randomLevel(); max_length++; //如果目前还没有节点 if (head == NULL) { //第一个节点的高度为max node* p = new node(val,MAXLEVEL); head = p; max_length++; } else { //指向第一个节点 node* cur = head; //p是新加入的节点 node* p = new node(val, level); //保存每一层插入的最近前面节点 //node** last=(node**)malloc(MAXLEVEL*sizeof(node*)); node* last[MAXLEVEL]; for (int i = MAXLEVEL-1; i >= 0; i--) { //在第i层找到最后一个比val小的节点 while (cur->forword[i] != NULL && cur->forword[i]->val < val) { cur = cur->forword[i]; } last[i] = cur; } //找到了 if(cur->forword[0]==NULL){ //插入到最后 for (int i = p->level-1; i >= 0; i--) { last[i]->forword[i] = p; } } else if (cur->forword[0]->val > val) { //插入 for (int i = p->level-1; i >= 0; i--) { //p的后面指针=p前面的指针的后续指针 p->forword[i] = last[i]->forword[i]; //改变p前面的指针的后续指针 last[i]->forword[i] = p; } } } } //从最高level开始找,若最高level找不到则level-- 直到level==0若还是找不到 则真找不到(cout<<"not find")。 void search(int val) { node* cur = head; for (int i = MAXLEVEL - 1; i >= 0; i--) { while (cur->forword[i]!=NULL&&cur->forword[i]->val<val) { cur = cur->forword[i]; } if (cur->forword[i]!=NULL&&cur->forword[i]->val == val) { cout << "i search it " << endl; return; } //else cout << "not find" << endl; } cout << "not find" << endl; } //方法与search一样,先找到要删除的值,若找到了改变前面的指针 void delete_val(int val) { node* cur = head; node* ask=NULL;//要找到的节点 node* last[MAXLEVEL]; for (int i = MAXLEVEL - 1; i >= 0; i--) { while (cur->forword[i] != NULL && cur->forword[i]->val < val) { cur = cur->forword[i]; } //保留每个level的前面的指针 last[i] = cur; if (cur->forword[i] != NULL && cur->forword[i]->val == val) { //找到了但是得保存前面的指针所以继续往下扫描 //保存找到的节点 ask = cur->forword[i]; } //else cout << "not find" << endl; } for (int i = ask->level - 1; i >= 0; i--) { //删除的节点前面的指针替换成删除的节点所指 last[i]->forword[i] = ask->forword[i]; } //释放内存 delete(ask); } //测试打印 void print() { for (int i = MAXLEVEL-1; i >= 0; i--) { node* cur = head; /*cout << cur->val;*/ while (cur->forword[i]) { cur = cur->forword[i]; cout << cur->val; } cout << endl; } //cout << head->get_val() << endl; //cout << max_length; } int get_max_length() { return max_length; } private: node* head; int max_length; };

    三、测试

    int main() { skiplist t1; t1.insert(3); t1.insert(7); t1.insert(4); t1.insert(6); t1.insert(5); t1.insert(-1); t1.delete_val(4); //cout << t1.get_max_length()<<endl; t1.search(8); //cout << endl; //t1.insert(10); //t1.insert(100); //t1.search(6); //t1.delete_val(4); t1.print(); system("pause"); return 0; }

    运行结果: 注:print()函数打印的为跳表从最左节点打到最后,从上往下打。 跳表实现成功!

    四、反思

    编写的时候出现了两个bug:

    二级指针的建立 我想用二级指针node** last来保存前面的节点(node*),或者是保存每个节点的forword指针,以便减少内存。结果导致debug时间一个小时,整个程序都是乱的。

    错误的初始化:

    node** forword; forword = (node**)malloc(sizeof(node*) * level);

    应当改为: 其中forword为node数组,node[0]:node,node[1]:node*… 数组的大小为level

    forword=new node*[level]; //forword为node*数组 level下标越界 for循环写成for(int i=level;i>=0;i++),应当为i=level-1
    Processed: 0.022, SQL: 8