数据结构自学笔记 链表超进化

Posted You Siki

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构自学笔记 链表超进化相关的知识,希望对你有一定的参考价值。

讲真,链表是个十分入门且简单的数据结构,虽然用的不多,但有时候还真非它莫属。

然而,作为一名C++选手,我的链表总是被各种大常数以及难写的代码困扰。

今天从算法导论上学来了点小技巧,赶紧代码实现了一下。

 

之前,我的链表都是这么写的。

 

class list
{
    struct node
    {
        int key;
        node *next;
        node *prev;
    };
    
    node *head;
    node *tail;
    
    list(void)
    {
        head = NULL;
        tail = NULL;
    }
    
    void insert_to_head(int k)
    {
        node *t = new node;
        
        t -> key = k;
        
        t -> prev = NULL;
        t -> next = head;
        
        if (head != NULL)
            head -> prev = t;
        
        head = t;
    }
    
    void insert_to_tail(int k)
    {
        node *t = new node;
        
        t -> key = k;
        
        t -> prev = tail;
        t -> next = NULL;
        
        if (tail != NULL)
            tail -> next = t;
            
        tail = t;
    }
    
    void delete_a_node(node *t)
    {
        if (t -> prev != NULL)
            t -> prev -> next = t -> next;
        else
            head = t -> next;
            
        if (t -> next != NULL)
            t -> next -> prev = t -> prev;
        else
            tail = t -> prev;
            
        delete(t);
    }
    
    node *find_the_key(int k)
    {
        node *t = head;
        
        while (t != NULL && t -> key != k)
            t = t -> next;
            
        return t;
    }
};

 

代码还是蛮好看的,自认为。然而接连不断地新建结点的常数总是让人吃不消。

 

于是,从Introduction to Algorithm中学来的第一招——用哨兵(哑结点)优化常数以及代码难度。

原来,我们经常用到一个表示空结点的NULL,而且为了防止非法访问,还要各种边界特判,烦不胜烦。

现在,我们新建一个名为NIL的哑结点,用来替代原来的所有NULL,省去了好多特判,代码也好写多了。重点是还能通过NIL把head和tail连在一起,形成了一个环状链表。

 

class list
{
    struct node
    {
        int key;
        node *next;
        node *prev;
    };
    
    node *nil;
    
    list(void)
    {
        nil = new node;
        
        nil -> key = -1;
        nil -> next = nil;
        nil -> prev = nil;
    }
    
    void insert_to_head(int k)
    {
        node *t = new node;
        
        t -> key = k;
        
        t -> prev = nil;
        t -> next = nil -> next;
        t -> next -> prev = nil -> next = t;
    }
    
    void insert_to_tail(int k)
    {
        node *t = new node;
        
        t -> key = k;
        
        t -> next = nil;
        t -> prev = nil -> prev;
        t -> prev -> next = nil -> prev = t;
    }
    
    void delete_a_node(node *t)
    {
        t -> prev -> next = t -> next;
        t -> next -> prev = t -> prev;
            
        delete(t);
    }
    
    node *find_the_key(int k)
    {
        node *t = nil -> next;
        
        while (t != nil && t -> key != k)
            t = t -> next;
            
        return t;
    }
};

 

后来,看到算法导论还说我们可以自己手写新建结点和释放结点函数,实现垃圾回收,感觉会快很多呢。我就顺便扩展了一下,实现了自动申请新的更多的空间。

 

class list
{
    struct node
    {
        int key;
        node *next;
        node *prev;
    };
    
    const static int lim = 1000000;
    
    node *nil;
    node *fre;
    
    void apply_more(void)
    {
        node *lst = new node[lim];
        
        for (int i = 0; i < lim; ++i)
        {
            lst[i].next = fre;
            fre = lst + i;
        }
    }
    
    node *new_node(void)
    {
        if (fre == NULL)
            apply_more();
            
        node *ret = fre;
        fre = fre -> next;
        
        return ret;    
    }
    
    void free_node(node *t)
    {
        t -> next = fre;
        fre = t;
    }
    
    list(void)
    {
        fre = NULL;
        
        nil = new_node();
        
        nil -> key = -1;
        nil -> next = nil;
        nil -> prev = nil;
    }
    
    void insert_to_head(int k)
    {
        node *t = new_node();
        
        t -> key = k;
        
        t -> prev = nil;
        t -> next = nil -> next;
        t -> next -> prev = nil -> next = t;
    }
    
    void insert_to_tail(int k)
    {
        node *t = new_node();
        
        t -> key = k;
        
        t -> next = nil;
        t -> prev = nil -> prev;
        t -> prev -> next = nil -> prev = t;
    }
    
    void delete_a_node(node *t)
    {
        t -> prev -> next = t -> next;
        t -> next -> prev = t -> prev;
            
        free_node(t);
    }
    
    node *find_the_key(int k)
    {
        node *t = nil -> next;
        
        while (t != nil && t -> key != k)
            t = t -> next;
            
        return t;
    }
};

 

@Author: YouSiki

以上是关于数据结构自学笔记 链表超进化的主要内容,如果未能解决你的问题,请参考以下文章

人工智能初学笔记系列:基础概念与进化流程

人工智能初学笔记系列:基础概念与进化流程

人工智能初学笔记系列:基础概念与进化流程

MFC 几大关键技术 自学笔记

LinkedHashMap,链表和哈希的合体进化

LinkedHashMap,链表和哈希的合体进化