1206. 设计跳表

skiplist插入形成过程

redis_skiplist_example (1).png

题目:1206. 设计跳表

题解:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

Redis内部数据结构详解(6)——skiplist - 铁蕾的个人博客

跳表:复杂链式结构:跳表_INGNIGHT的博客-CSDN博客

class Skiplist {
    int MAX_LEVEL;
public:
    Skiplist() {
        MAX_LEVEL = 16;
        _max_level = 1;
    }
    
    bool search(int target) {
        std::vector<Node*> prevs = find(target);
        return prevs[0]->forward[0] && prevs[0]->forward[0]->val == target ? true : false;
    }
    
    void add(int num) {
        int level = get_level();
        _max_level = std::max(_max_level, level);
        //cout << _max_level << endl;
        std::vector<Node*> prevs = find(num);
        Node * node = new (std::nothrow) Node;
        node->val = num;
        for (int i = level-1; i >= 0; --i) {
            node->forward[i] = prevs[i]->forward[i];
            prevs[i]->forward[i] = node;
        }
    }
    
    bool erase(int num) {
        std::vector<Node*> prevs = find(num);
        if (!prevs[0]->forward[0] || prevs[0]->forward[0]->val != num) {
            return false;
        }
        for (int i = _max_level-1; i >= 0; --i) {
            if (prevs[i]->forward[i] && prevs[i]->forward[i]->val == num) {
                prevs[i]->forward[i] = prevs[i]->forward[i]->forward[i];
            }
        }
        //delete prevs[0]->forward[0];
        while (_max_level > 1 && !head.forward[_max_level-1]) {
            --_max_level;
        }
        return true;
    }
    struct Node {
        Node() {
            val = -1;
            forward.resize(16, nullptr);
        }
        std::vector<Node*> forward;
        int val;
    };
    int get_level() {
        int level = 1;
        while (random() / RAND_MAX < 0.5 && level < MAX_LEVEL) {
            ++level;
        }
        // 最大的高度也就是0~15
        return level;
    }
    std::vector<Node*> find(int target) {
        Node* cur = &head;
        std::vector<Node*> result(_max_level, nullptr);
        for (int i = _max_level-1; i >= 0; --i) {
            while (cur->forward[i] && cur->forward[i]->val < target) {
                cur = cur->forward[i];
            }
            result[i] = cur;
        }
        return result;
    }
    Node head;
    int _max_level;
};

/**
 * Your Skiplist object will be instantiated and called as such:
 * Skiplist* obj = new Skiplist();
 * bool param_1 = obj->search(target);
 * obj->add(num);
 * bool param_3 = obj->erase(num);
 */
static const int SKIPLIST_P_VAL = RAND_MAX / 2, MAX_LEVEL = 16;
class Skiplist {
public:
    struct Node {
        int val;
        vector<Node *> level;
        Node(int val, int size = MAX_LEVEL) : val(val), level(size) {}
    };

    Node head;
    int maxlevel = 1;
    Skiplist() : head(INT_MIN, MAX_LEVEL) {}
    // ~Skiplist() { delte all nodes. }

    // essentially the same as _search
    bool search(int target) {
        Node * prev = _search(target)[0];
        return prev->level[0] && prev->level[0]->val == target;
    }

    vector<Node *> _search(int key) {
        Node * cur = &head;
        vector<Node *> prevs(MAX_LEVEL);
        // through every level, from top to bottom
        for (int i = maxlevel - 1; i >= 0; i--) {
            // through elements in the current level with smaller value
            while (cur->level[i] && cur->level[i]->val < key)
                cur = cur->level[i];
            prevs[i] = cur;
        }

        return prevs;
    }

    void add(int num) {
        auto prevs = _search(num);
        int level = random_level();
        // update maxlevel and prevs
        if (level > maxlevel) {
            for (int i = maxlevel; i < level; i++)
                prevs[i] = &head;
            maxlevel = level;
        }
        Node * cur = new Node(num, level);
        // from prev->next   to   prev->cur->next
        for (int i = level - 1; i >= 0; i--) {
            cur->level[i] = prevs[i]->level[i];
            prevs[i]->level[i] = cur;
        }
        // if there is backward pointer, need to set both cur and cur.next 's back pointer
        // Note that the back poinet of the first valid node is nullptr instead of head
    }
    
    bool erase(int num) {
        auto prevs = _search(num);
        if (!prevs[0]->level[0] || prevs[0]->level[0]->val != num)
            return false;
        Node * del = prevs[0]->level[0];
        // from prev->cur->next to prev->next
        for (int i = 0; i < maxlevel; i++)
            if (prevs[i]->level[i] == del)
                prevs[i]->level[i] = del->level[i];
        delete del;
        // update maxlevel.
        while (maxlevel > 1 && !head.level[maxlevel - 1])
            maxlevel--;
        // if there is backward poinet, need to set cur.next.back to cur.back
        return true;
    }

    static int random_level() {
        int level = 1;
        while (rand() < SKIPLIST_P_VAL && level < MAX_LEVEL) level++;
        return level;
    }
};
constexpr int MAX_LEVEL = 32;
constexpr double P_FACTOR = 0.25;

struct SkiplistNode {
    int val;
    vector<SkiplistNode *> forward;
    SkiplistNode(int _val, int _maxLevel = MAX_LEVEL) : val(_val), forward(_maxLevel, nullptr) {
        
    }
};

class Skiplist {
private:
    SkiplistNode * head;
    int level;
    mt19937 gen{random_device{}()};
    uniform_real_distribution<double> dis;

public:
    Skiplist(): head(new SkiplistNode(-1)), level(0), dis(0, 1) {

    }

    bool search(int target) {
        std::vector<SkiplistNode*> update = find(target);
        return update[0]->forward[0] && update[0]->forward[0]->val == target ? true : false;
    }

    void add(int num) {
        /*vector<SkiplistNode *> update(MAX_LEVEL, head);
        SkiplistNode *curr = this->head;
        for (int i = level - 1; i >= 0; i--) {
            // 找到第 i 层小于且最接近 num 的元素
            while (curr->forward[i] && curr->forward[i]->val < num) {
                curr = curr->forward[i];
            }
            update[i] = curr;
        }*/
        int lv = randomLevel();
        level = max(level, lv);
        vector<SkiplistNode *> update = find(num);
        SkiplistNode *newNode = new SkiplistNode(num, lv);
        for (int i = lv-1; i >= 0; --i) {
            /* 对第 i 层的状态进行更新,将当前元素的 forward 指向新的节点 */
            newNode->forward[i] = update[i]->forward[i];
            update[i]->forward[i] = newNode;
        }
    }

    bool erase(int num) {
        vector<SkiplistNode *> update = find(num);
        SkiplistNode* curr = update[0]->forward[0];
        if (!curr || curr->val != num) {
            return false;
        }
        for (int i = level-1; i >= 0; --i) {
            if (update[i]->forward[i] == curr) {
                /* 对第 i 层的状态进行更新,将 forward 指向被删除节点的下一跳 */
                update[i]->forward[i] = curr->forward[i];
            }
        }
        delete curr;
        /* 更新当前的 level */
        while (level > 1 && head->forward[level - 1] == nullptr) {
            level--;
        }
        return true;
    }

    int randomLevel() {
        int lv = 1;
        /* 随机生成 lv */
        while (dis(gen) < P_FACTOR && lv < MAX_LEVEL) {
            lv++;
        }
        return lv;
    }

    std::vector<SkiplistNode*> find(int target) {
        SkiplistNode* cur = head;
        std::vector<SkiplistNode*> result(level, nullptr);
        for (int i = level-1; i >= 0; --i) {
            while (cur->forward[i] && cur->forward[i]->val < target) {
                cur = cur->forward[i];
            }
            result[i] = cur;
        }
        return result;
    }
};

陈小玉代码:

#include<cstdio>
#include<cstdlib>//rand()
#include<ctime>//time()
using namespace std;
const int INF=0x7fffffff;
const float P=0.5f;
const int MAX_LEVEL=16;
using namespace std;

typedef struct Node{
	int val;
	struct Node *forward[MAX_LEVEL];
}*Nodeptr;

Nodeptr head,updata[MAX_LEVEL];
int level;

void Init(){
	level=0;
	head=new Node;
	for(int i=0;i<MAX_LEVEL;i++)
		head->forward[i]=NULL;
	head->val=-INF;
}

int RandomLevel(){//随机产生插入元素高度 
	int lay=0;
	//printf("%d\n",rand());
	//printf("%d\n",RAND_MAX);
	while((float)rand()/RAND_MAX<P&&lay<MAX_LEVEL-1)//rand()产生的随机数范围是0~RAND_MAX
		lay++;	
	return lay;
}

Nodeptr Find(int val){//查找最接近val的元素 
	Nodeptr p=head;
	for(int i=level;i>=0;i--){
		while(p->forward[i]&&p->forward[i]->val<val)
			p=p->forward[i];
		updata[i]=p;//记录搜索过程中各级走过的最大节点位置 
	}
	return p; 
}

void Insert(int val){
	Nodeptr p,s;
	int lay=RandomLevel();
	printf("lay=%d\n",lay);
	if(lay>level) //要插入的层 > 现有层数
		level=lay;
	p=Find(val); //查询 
	s=new Node;//创建一个新节点 
	s->val=val;
	for(int i=0;i<MAX_LEVEL;i++)
		s->forward[i]=NULL;
	for(int i=0;i<=lay;i++){//插入操作
		s->forward[i]=updata[i]->forward[i];
		updata[i]->forward[i]=s;
	}
}

void Delete(int val){
	Nodeptr p=Find(val);
	if(p->forward[0]&&p->forward[0]->val==val){
		printf("%d\n",p->forward[0]->val);
		for(int i=level;i>=0;i--){//删除操作 
			if(updata[i]->forward[i]&&updata[i]->forward[i]->val==val)
				updata[i]->forward[i]=updata[i]->forward[i]->forward[i];
		}
		while(level>0&&!head->forward[level])//删除空链 
			level--;
	}
}

void print(int i){//遍历 
	Nodeptr p=head->forward[i];
	if(!p) return;
	while(p){
		printf("%d  ",p->val);
		p=p->forward[i];
	}
	printf("\n");
}

void printall(){//遍历所有层 
	for(int i=level;i>=0;i--)
		printf("level %d:  ",i),print(i);	
}

void show(){
	printf("Please select:\n");
	printf("-----------------------------\n");
	printf("     1:  插入\n");
	printf("     2:  删除\n");
	printf("     3:  查找\n");
	printf("     4:  遍历\n");
	printf("     5:  遍历所有层\n");
	printf("     0:  退出\n");
	printf("-----------------------------\n");
}

int main(){
	//time函数返回从1970年1月1日0时开始到现在逝去的秒数
	//可以利用srand((unsigned int)(time(NULL))的方法,产生不同的随机数种子,因为每一次运行程序的时间是不同的
	srand((unsigned int)time(0));
	Init();
	int n,x;
	show();
    while(~scanf("%d",&n),n){
        switch(n){
	        case 1:
	            scanf("%d",&x);
				Insert(x);break;
	        case 2:
	        	scanf("%d",&x);
	            Delete(x);break;
	        case 3:
	            scanf("%d",&x);
	            Nodeptr p;
				p=Find(x);
				if(p->forward[0]&&p->forward[0]->val==x)
					printf("find success!\n");
				else
					printf("find fail!\n");
				break;
	        case 4:
	            print(0);break;
	        case 5:
	            printall();break;  
        }
        show();
    }
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值