数据结构与算法--跳表

先贴上一个跳表的实现

包括:初始化、插入、删除、搜索、整理

这是头文件

#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 << "\n";
        }
        //打印结束,换行
        output << "\n";
        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 << " 测试初始化:\n";
    skiplist<string> sl;

    cout << " 测试插入:\n";
    for (int i = 1; i <= 100; i++) {
        cout <<sl.insert(i, "hhh");
    }

    cout << " \n测试输出运算符重载:\n";
    cout << endl<<sl;

    cout << " \n测试搜索功能:\n";
    cout << "键100的数据:" << sl.search(100) << endl;

    cout << " \n测试删除功能:\n";
    cout <<" 删除4号键值对:" <<sl.deleteSL(4) << endl;
    cout << sl;

    cout << " \n测试整理功能:\n";
    cout<<sl.formate();
    cout <<"\nformated:\n" <<sl;
    system("pause");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/trialley/p/10541824.html
今日推荐