目录
一、链表
- 链表是一种常用的数据结构,它通过指针将一些列数据结点,连接成一个数据链。相对于数组,链表具有更好的动态性。
- 数据域用来存储数据,指针域用于建立与下一个结点的联系。
数组和链表的区别:
数组:一次性分配一块连续的存储区域。
优点:随机访问元素效率高
缺点:1) 需要分配一块连续的存储区域(很大区域,有可能分配失败)
2) 删除和插入某个元素效率低
链表:无需一次性分配一块连续的存储区域,只需分配n块节点存储区域,通过指针建立关系。
优点:1) 不需要一块连续的存储区域
2) 删除和插入某个元素效率高
缺点:随机访问元素效率低
二、链表的分类
2.1 链表分为:静态链表和动态链表
- 所有结点都是在程序中定义的,不是临时开辟的,也不能用完后释放,这种链表称为“静态链表”。
- 所谓动态链表,是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。
静态链表
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//节点的结构体
struct LinkNode
{
int num; //数据域
struct LinkNode * next; //指针域
};
void test01()
{
//创建节点
struct LinkNode node1 = { 10, NULL };
struct LinkNode node2 = { 20, NULL };
struct LinkNode node3 = { 30, NULL };
struct LinkNode node4 = { 40, NULL };
struct LinkNode node5 = { 50, NULL };
//建立关系
node1.next = &node2;
node2.next = &node3;
node3.next = &node4;
node4.next = &node5;
//遍历链表
struct LinkNode * pCurrent = &node1;
while (pCurrent != NULL)
{
printf("%d\n", pCurrent->num);
pCurrent = pCurrent->next;
}
}
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
动态链表
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct LinkNode
{
int num;
struct LinkNode * next;
};
void test01()
{
//创建节点
struct LinkNode * node1 = malloc(sizeof(struct LinkNode));
struct LinkNode * node2 = malloc(sizeof(struct LinkNode));
struct LinkNode * node3 = malloc(sizeof(struct LinkNode));
struct LinkNode * node4 = malloc(sizeof(struct LinkNode));
struct LinkNode * node5 = malloc(sizeof(struct LinkNode));
//给数据域赋值
node1->num = 100;
node2->num = 200;
node3->num = 300;
node4->num = 400;
node5->num = 500;
//建立关系
node1->next = node2;
node2->next = node3;
node3->next = node4;
node4->next = node5;
node5->next = NULL;
//遍历链表
struct LinkNode * pCurrent = node1;
while (pCurrent!=NULL)
{
printf("%d\n", pCurrent->num);
pCurrent = pCurrent->next;
}
free(node1);
free(node2);
free(node3);
free(node4);
free(node5);
node1 = NULL;
node2 = NULL;
node3 = NULL;
node4 = NULL;
node5 = NULL;
}
int main(){
test01();
system("pause");
return EXIT_SUCCESS;
}
2.2 带头和不带头链表
带头链表:固定一个节点作为头结点(数据域不保存有效数据),起一个标志位的作用,不管链表节点如果改变,此头结点固定不变。
不带头链表:头结点不固定,根据实际需要变换头结点(如在原来头结点前插入新节点,新节点重新作为链表的头结点)。
2.3 单向链表、双向链表、循环链表
单向链表:
- 单链表有两个特殊的结点,分别是第一个结点——头结点和最后一个结点——尾结点。
- 头结点:用来记录链表的基地址。
- 尾结点:尾结点的后继指针指向一个空地址NULL。
双向链表
- 单链表和双向链表的区别
- 单链表的结点只有一个指向,即后继指针next指向下一个结点。
- 双向链表的结点有两个指向,一个后继指针next指向下一个结点,还有一个前驱指针prev指向上一个结点
循环链表
循环链表的尾结点不指向空,而是指向头结点,类似一个环形结构。
三、链表总结
- 由于链表的内存空间是零散的,所以不支持随机访问。
- 插入、删除不需要移动数据,所以效率高。
- 因为链表的每个内存块都不是连续的,所以不需要提前计算内存的大小,内存空间可以根据结点数量的改变而改变。