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

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

然而,作为一名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

原文地址:https://www.cnblogs.com/yousiki/p/6095981.html