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

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

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

时间: 2024-12-23 23:04:47

数据结构自学笔记 链表超进化的相关文章

Java自学笔记(四)—— 集合类总结

今天来总结总结Java集合类.集合类又叫容器类,它封装了很多我们学过的数据结构,这些现成的集合类,实现了各种操作,使用起来非常方便,今天的总结也是以代码为主. 集合大致分为Set.List.Map三种体系.但实际上Java集合类主要由两个接口派生而出,Collection接口和Map接口. Collection接口的子接口: 1.Set,无序,元素不可重复 2.Queue 队列 3.List,有序,元素可以重复 一个个来细说,Set,可以想像成是一个大箱子,里面的东西是无序的,但是有一个条件就是

小猪的数据结构学习笔记(四)

小猪的数据结构学习笔记(四) 线性表之静态链表 --转载请注明出处:coder-pig 本章引言: 在二,三中中我们分别学习了顺序表中的线性表与单链表,线性表有点类似于 我们前面所学的数组,而单链表使用的最多的是指针,这里问个简单的问题, 如果是在以前没有指针的话,前辈先人们怎么实现单链表呢?大家思考下! 没有指针,那么用什么来代替呢?前辈先人们非常机智,想出了使用下标+游标的方式 来实现单链表的效果!也就是今天要讲的--静态链表! 当然你也可以直接跳过本章,因为有了单链表就没有必要用静态链表了

小猪的数据结构学习笔记(二)

小猪的数据结构学习笔记(二) 线性表中的顺序表 本节引言: 在上个章节中,我们对数据结构与算法的相关概念进行了了解,知道数据结构的 逻辑结构与物理结构的区别,算法的特性以及设计要求;还学了如何去衡量一个算法 的好坏,以及时间复杂度的计算!在本节中我们将接触第一个数据结构--线性表; 而线性表有两种表现形式,分别是顺序表和链表;学好这一章很重要,是学习后面的基石; 这一节我们会重点学习下顺序表,在这里给大家一个忠告,学编程切忌眼高手低,看懂不代表自己 写得出来,给出的实现代码,自己要理解思路,自己

python自学笔记

python自学笔记 python自学笔记 1.输出 2.输入 3.零碎 4.数据结构 4.1 list 类比于java中的数组 4.2 tuple 元祖 5.条件判断和循环 5.1 条件判断 5.2 循环 6.使用dict和set 6.1 dict 6.2 set 7.函数的使用 7.1函数返回多个值,同时接受多个值 7.2函数参数的默认值 7.3可变参数的函数 7.4可变个数带参数名的入参 7.5参数类型组合 8.关于函数递归 9.python的高级特性 9.1切片 9.2遍历 9.3列表生

python自学笔记(一)

我没学过python,通过网上和一些图书资料,自学并且记下笔记. 很多细节留作以后自己做项目时再研究,这样能更高效一些. python基础自学笔记 一.基本输入和输出 pthon3.0用input提示用户输入,用print提示用户输出,格式为print("...") 如果格式化输出,那么格式为print("%d" %(变量名)), %d可以替换为%s等其他格式符, 以后用到什么格式自己查,这样学起来高效. 简单的例子: #-*-coding:utf-8-*- nam

小猪的数据结构学习笔记(五)

小猪的数据结构学习笔记(五) 线性表之--循环链表                           --转载请注明出处:coder-pig 循环链表知识点归纳: 相关代码实现: ①判断是否为空表: ②单循环链表的存储结构 其实和单链表的结构是一样的! /*定义循环链表的存储结构*/ typedef struct Cir_List { int data; struct Cir_List *next; }Lnode; ③初始化循环单链表 代码如下: //1.循环链表的初始化 //表示一个元素,如

数据结构学习笔记——线性表的应用

数据结构学习笔记——线性表的应用 线性表的应用 线性表的自然连接 计算任意两个表的简单自然连接过程讨论线性表的应用.假设有两个表A和B,分别是m1行.n1列和m2行.n2列,它们简单自然连接结果C=A*B(i==j),其中i表示表A中列号,j表示表B中的列号,C为A和B的笛卡儿积中满足指定连接条件的所有记录组,该连接条件为表A的第i列与表B的第j列相等. 如:         1 2 3                3 5 A  =  2 3 3         B =  1 6       

大话数据结构读书笔记

大话数据结构读书笔记 编程基础: 数据结构 算法 1 线性表 //顺序储存结构的结构代码: #define MAXSIZE 20//储存空间的起始分配量 typedef int ElemType;//ElemType类型根据实际类型而定,这里假设是int typedef struct{ ElemType data[MAXSIZE];//数组储存元素,最大值为MAXSIZE int length;/线性表当前长度: }SqList; //顺序存储结构需要三个属性: //1存储空间的起始位置:数组d

小猪的数据结构学习笔记(三)

小猪的数据结构学习笔记(三) 线性表之单链表 本章引言: 上一节中我们见识了第一个数据结构--线性表中的顺序表; 当你把操作的代码自己写几遍就会有点感觉了,如果现在让你写顺序表的 插入算法,你能够想出大概的代码么?如果可以,那么你就可以进入新的章节了; 否则,还是回头看看吧!在本节,我们将迎来线性表的链式表示--单链表 单链表和顺序表有什么优势和劣势呢?单链表的头插法和尾插法有什么不同呢? 请大家跟随笔者的脚步来解析线性表中的单链表把! 本节学习路线图 路线图解析: ①先要理解顺序表和单链表各自