链表是什么?
**链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。 相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。链表可以在多种编程语言中实现。像Lisp和Scheme这样的语言的内建数据类型中就包含了链表的存取和操作。程序语言或面向对象语言,如C,C++和Java依靠易变工具来生成链表。**
链表基础操作
首先我们要想,一个结点里面要有什么?
一个是数据域,第二个是指针域,指向下一个结点,所以我们用一个结构体来包括一个结点所需要的这些内容。
这是链表中的一个结点的内容
SListDataType这个类型,是用户自定义类型,可以是int ,double,char,还可以是一个结构体类型。
而这个结构体里,就是链表的创建,里面是第一个结点的指针。
初始化,首先传一个链表的结构体指针,第一步判断指针是否为空,此处用断言判断,第二步初始化,给第一结点指空。
头插,时间复杂度为O(1),传进来连边的结构体指针,和要给结点里附的值。
一 创建新结点。二新的结点里的数据域里附传进来的值三新建结点的指针域指向第一个结点四第一个结点指向新建结点,让新建结点作为新的链表的第一个结点
尾插,有循环,O(n)
一,创建新结点,新结点数据域赋值,新结点指针域指控。
二,判断链表是否为空,如果为空,把让链表的第一个结点指针指向新建的结点。
三,找最后一个结点,隐藏着链表一定有结点,创建一个新指针指向链表第一个结点,当指针不为空时,指针往后移。循环结束后,最后一个结点的指针域指向新建结点
头删
一,首先判断,如果没有链表,没有结点不能删。
二 新建指针指向第一个结点的下一个结点.
三 释放第一个结点。
四 第一个结点指向新建指针。
尾删 O(n)
一,首先判断第一个结点 assert(s != NULL); // 不能没有链表assert(s->first != NULL); 不能没有结点二,如果链表中只有一个结点,直接释放三,否则,创建新指针指向头结点,**当下下一个结点不为空,指针指向下一个。释放下一个结点**,最后指空
查找
一 遍历链表,找到数据域里的值相同时,返回。
删除多个值相同的结点
一判断是否为空
二 判断是否只为一个结点
三 创建新指针cur指向第一个结点,当该结点下一个不为空时,如果结点下一个的数据域里的值等于要删的值,创建新指针指向下下一个结点
四 然后释放当前结点,并让cur指向下一个结点。