欢迎来到陈宇翔的博客

人生三从境界:昨夜西风凋碧树,独上高楼,望尽天涯路。 衣带渐宽终不悔,为伊消得人憔悴。 众里寻他千百度,蓦然回首,那人却在灯火阑珊处。
扩大
缩小

数据结构与算法--跳跃链表

一、什么是跳表

跳跃列表(也称跳表)是一种随机化数据结构,基于并联的链表,其效率可比拟于二叉查找树(对于大多数操作需要O(log n)平均时间)。

基本上,跳跃列表是对有序的链表增加上附加的前进链接,增加是以随机化的方式进行的,所以在列表中的查找可以快速的跳过部分列表,因此得名。所有操作都以对数随机化的时间进行。

跳跃列表是按层建造的。底层是一个普通的有序链表。每个更高层都充当下面列表的“快速跑道”,这里在层 i 中的元素按某个固定的概率 p (通常为0.5或0.25)出现在层 i+1 中。平均起来,每个元素都在 1/(1-p) 个列表中出现,而最高层的元素(通常是在跳跃列表前端的一个特殊的头元素)在 O(log1/pn) 个列表中出现。例如在下面的跳表中寻找元素12:

 


二、具体实现

ps:此实现中跳表的层数我假设从1层开始,但是存储的时候由于使用的是数组,因此与实际相差1.

/*节点类*/
class SlipNode {
public:
    SlipNode() {
    };
    SlipNode(int level, int k, int value);
    ~SlipNode();

public:
    int m_k;
    int m_value;
    int m_level;
    SlipNode** m_ppforward;              //可变前向指针数组 
};

SlipNode::SlipNode(int level, int k, int value) :m_k(k), m_value(value) {
    m_level = level < 1 ? 1 : level;
    m_ppforward = new SlipNode*[m_level];
    for (int i = 0; i < m_level; ++i) {
        m_ppforward[i] = NULL;
    }
}

SlipNode::~SlipNode() {
    cout << "index:" << m_k << " is deleted!" << endl;
    if (m_ppforward)
        delete[] m_ppforward;
    m_ppforward = NULL;
}
/*跳表*/
class SlipList {
public:
    SlipList(const int maxlevel = 16, const int maxbit = 32);
    ~SlipList();
    void Insert(const int& key, const int& value);
    void Delete(const int& key);
    void Display();
    int Random();
    int SearchValue(const int& k);                //根据索引关键字返回值,如果不存在则返回-1 
    SlipNode* SearchNode(const int& value);    //根据值返回节点,如果不存在则返回NULL 

private:
    int RandomLevel();

private:
    SlipNode* m_phead;
    int m_level;                            //这是实际的层数,总比数组中存储的值大一
    const int MAX_LEVEL;
    const int MAX_BIT;
    int m_random_bit;
    int m_bit_left;
};

SlipList::SlipList(const int maxlevel, const int maxbit) :m_level(1), MAX_LEVEL(maxlevel), MAX_BIT(maxbit), m_bit_left(MAX_BIT) {
    m_phead = new SlipNode(MAX_LEVEL, -1, -1);
    m_random_bit = Random();
}

SlipList::~SlipList() {
    if (m_phead) {
        SlipNode* p = m_phead;
        while (p) {
            m_phead = p->m_ppforward[0];
            delete p;
            p = m_phead;
        }
    }
}

int SlipList::Random() {
    srand(time(0));
    return rand();
}

int SlipList::RandomLevel() {
    int level = 1;
    int b;
    do {
        b = m_random_bit & 3;                //1/4概率为0,也就是说层数增加的概率是(1/4)^n 
        if (!b)
            level++;
        m_random_bit >>= 2;
        m_bit_left -= 2;
        if (m_bit_left == 0) {
            m_random_bit = Random();
            m_bit_left = MAX_BIT;
        }
    } while (!b);
    return (level > (MAX_LEVEL - 1) ? (MAX_LEVEL - 1) : level);
}

int SlipList::SearchValue(const int& k) {
    int l = m_level;
    SlipNode* p = m_phead;
    SlipNode* q = NULL;
    while (l > 0) {
        while ((p = p->m_ppforward[l-1]) && (p->m_k < k)) q = p;
        l--;
    }
    if (!q || q->m_k != k) {
        return -1;
    }
    return q->m_value;
}

SlipNode* SlipList::SearchNode(const int& value) {
    int l = m_level;
    SlipNode* p = m_phead;
    SlipNode* q = NULL;
    while (l > 0) {
        while ((q = p->m_ppforward[l-1]) && (q->m_value < value)) p = q;
        l--;
    }
    if (!q || q->m_value != value) {
        return NULL;
    }
    return q;
}

void SlipList::Insert(const int& key, const int& value) {
    int l = m_level;
    SlipNode** update = new SlipNode*[MAX_LEVEL];
    SlipNode* p = m_phead;
    SlipNode* q = NULL;
    int level = RandomLevel();

    while (l > 0) {
        while (q = p->m_ppforward[l - 1]) {
            if(q->m_value < value)
                p = q;
            
        }
        update[l-1] = p;
        l--;
    }

    if (q && q->m_value == value) {
        q->m_value = value;
        delete[] update;
        update = NULL;
        return;
    }

    if (level > m_level) {
        level = ++m_level;                        //这个地方有小问题,因为毕竟层次是有限的,如果m_level+1后大于MAX_LEVEL 
        update[level-1] = m_phead;                //就会出错,但是层数越大概率越小,因此可近乎认为不可能超过MAX_LEVEL 
    }

    q = new SlipNode(level, key, value);
    while (level > 0) {
        p = update[level-1];
        q->m_ppforward[level-1] = p->m_ppforward[level-1];
        p->m_ppforward[level-1] = q;
        level--;
    }
    delete[] update;
    update = NULL;
}

void SlipList::Delete(const int& key) {
    int level = m_level;
    int curlevel = m_level;
    SlipNode** update = new SlipNode*[MAX_LEVEL];
    SlipNode* p = m_phead;
    SlipNode* q = NULL;

    while (level > 0) {
        while ((q = p->m_ppforward[level-1]) && (q->m_k < key)) p = q;
        update[level-1] = p;
        level--;
    }

    if (q->m_k != key) {
        delete[] update;
        update = NULL;
        return;
    }

    for (level = 1; level <= curlevel && (p = update[level-1])->m_ppforward[level-1] == q; ++level) {
        p->m_ppforward[level-1] = q->m_ppforward[level-1];
    }
    delete q;

    while (curlevel > 0 && m_phead->m_ppforward[curlevel-1] == NULL) {
        curlevel--;
    }
    m_level = curlevel;
    delete[] update;
    update = NULL;
}

void SlipList::Display() {
    cout << "list level:" << m_level << endl;
    for (SlipNode* p = m_phead->m_ppforward[0]; p; p = p->m_ppforward[0]) {
        cout << "key: " << p->m_k << " value: " << p->m_value << " level: " << p->m_level << endl;
    }
}

上述代码在vs2015环境下测试通过,一下是测试代码:

/*测试*/
int main(int argc, char* argv[]) {
    SlipList* list = new SlipList();
    for (int i = 1; i <= 5; ++i) {
        list->Insert(i, i + 100);
    }
    list->Display();
    list->Delete(2);
    cout << "delete key = 2:" << endl;
    list->Display();
    delete list;
    list = NULL;

    system("pause");
    return 0;
}

 

三、总结:

从这个程序我认识到:
1、指针数组在堆中分配后,必须手动销毁每一个指针,不能指望delete[]整个数组来释放所有内存;
2、使用类的初始化表达式时,不能假设编译器先对哪个变量的赋值,血的教训!!
3、同时我也学会了动态申请指针数组

出彩的地方:
使用 “&” 方法来模拟概率:如任意数和3(二进制)相与,只用四分之一的可能的到0.

问题:
指针变量在生命周期结束后不会自动调用析构函数???

问题的解:
重新回顾对象析构函数何时调用:
1、对象生命周期结束后(对于在栈中创建的对象)
2、指针所指向的在堆中分配的对象,必须手动调用delete来释放内存,此时才会调用析构函数
3、如果a是b的成员,那么当b的析构函数被调用时,a的析构函数也会被调用。

 

四、资料引用

条目一(什么是跳表)内容来自于 《作者:xiao囡囡  来源:CSDN  原文:https://blog.csdn.net/kuaile123/article/details/22584477》

 

posted on 2019-03-02 19:26  紫翼之狮  阅读(491)  评论(0编辑  收藏  举报

导航