链表的定义和特点
链表定义
和数组一样,链表也是一种线性表。
- 从内存结构来看,链表的内存结构是不连续的内存空间,是将一组零散的内存块串联起来,从而进行数据存储的数据结构。
- 每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域,即后继指针next和前驱指针prev
链表特点
- 链表在插入、删除的时候可以达到O(1)的复杂度,查找一个节点或者访问特定编号的节点则需要O(n)的时间;而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)。
- 链表的结点可以在运行时动态生成,可以克服数组链表需要预先知道数据大小的缺点,以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
- 链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的存取往往要在不同的排列顺序中转换。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。
与数组的选择,为时空替换思想:“用空间换时间” 与 “用时间换空间”
链表分类
1.单链表
1)每个节点只包含一个指针,即后继指针。
2)单链表有两个特殊的节点,即首节点和尾节点。用首节点地址表示整条链表,尾节点的后继指针指向空地址null。
3)性能特点:插入和删除节点的时间复杂度为O(1),查找的时间复杂度为O(n)。
2.循环链表
1)除了尾节点的后继指针指向首节点的地址外均与单链表一致。
2)适用于存储有循环特点的数据。
3.双向链表
1)节点除了存储数据外,还有两个指针分别指向前一个节点地址(前驱指针prev)和下一个节点地址(后继指针next)。
2)首节点的前驱指针prev和尾节点的后继指针均指向空地址。
3)性能特点
- 和单链表相比,存储相同的数据,需要消耗更多的存储空间。
- 插入、删除操作比单链表效率更高O(1)级别(双向链表可以直接找到前驱节点,时间复杂度为O(1))。
-对于一个有序链表,双向链表的按值查询效率要比单链表高一些。因为我们可以记录上次查找的位置p,每一次查询时,根据要查找的值与p的大小关系,决定是往前还是往后查找,所以平均只需要查找一半的数据。
4.双向循环链
首节点的前驱指针指向尾节点,尾节点的后继指针指向首节点。
键
链表的实现
链表的实现一般两种方法,数组实现和指针实现
数组实现:
void insert(int x, int i) { //把数据x插到第i个数据后面
a[cur++].node = x;
a[cur].next = a[i].next;
a[i].next = cur;
a[cur].prev = i;
a[a[cur].next].prev = cur;
}
void delete() {
a[a[cur].prev].next = a[cur].next;
a[a[cur].next].prev = a[cur].prev;
}
指针实现:
typedef struct rec {
int data;
struct rec *next;
struct rec *prev;
} LinkList;
LinkList *creat(int n) { //初始化一个链表
LinkList *head, *end, *cur;
head = end = NULL;
for (i = 1; i <= n; i++) {
cur = (LinkList *) malloc(sizeof(LinkList));
scanf("%d", &cur -> data);
if (!head) head = cur; else end -> next = cur;
end = cur;
}
if (end) end -> next = NULL;
return(head);
}
插入
void insert( LinkList* L, int x ) { //默认有头节点
LinkList *t = L -> Next;
LinkList *last = L;
LinkList *cur;
while ((t != NULL) && (t -> Data < x)) {
last = t;
t = t -> Next;
}
cur = (List *) malloc(sizeof(List));
cur -> Data = x;
cur -> Next = last -> Next;
last -> Next = cur;
}
删除
LinkList* delete(LinkList* L, int x ) {//删除所有数值为x的结点
LinkList *p, *cur;
while ((head) && (head -> data == x)) head = head -> next;
p = head;
while (p) {
cur = p -> next;
while ((cur) && (cur -> data == x)) cur = cur -> next;
p -> next = cur;
p = cur;
}
return(head);
——Eirlys