数据结构系列文章目录
文章目录
前言
本文摘自《王道数据结构》PPT和视频,经过自己总结后当做笔记和学习来用。
顺序表可以随时存取表中的任意一个元素,它的存储位置可以用一个简单直观的公式表示,但插入和删除操作需要移动大量元素。链式存储线性表时,不需要使用地址连续的存储单元,即不要求逻辑上相邻的元素在物理位置上也相邻,它通过“链”建立起数据元素之间的逻辑关系,因此插入和删除操作不需要移动元素,而只需修改指针,但也会失去顺序表可随机存取的优点。
上图摘自:博客
结点只有一个指针域的链表,称为单链表或线性链表
有两个指针域的链表,称为双链表。
首尾相接的链表称为循环链表。
头指针是指向链表中第一个结点的指针。
首元结点是指链表中存储第一个数据元素a1的结点。
头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息。
一、链表的定义
线性表的链式存储又称单链表,它是通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。
data为数据域,存放数据元素;next为指针域,存放其后继结点的地址。
单链表结点结构:
单链表中结点类型的描述:
typedef struct LNode{ //定义单链表结点类型
ElemType data; //数据域
struct LNode *next; //指针域
}LNode, *LinkList;
利用单链表可以解决顺序表需要大量连续存储单元的缺点,但单链表附加指针域,也存在浪费存储空间的缺点。由于单链表的元素离散地分布在存储空间中,所以单链表是非随机存取的存储结构,即不能直接找到表中某个特定的结点。查找某个特定的结点时,需要从表头开始遍历,依次查找。
二、单链表上基本操作的实现
1.采用头插法建立单链表
该方法是从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即头结点之后。
头插法建立单链表的算法如下:
LinkList List_HeadInsert(LinkList &L){ //逆向建立单链表
LNode *s; int x;
L=(LinkList)malloc(sizeof(LNode)); //创建头结点
L—>next=NULL; //初始为空链表
scanf("%d",&x); //输入结点的值
while(x!=9999){ //输入9999表示结束
s=(LNode*)malloc(sizeof(LNode));//创建新结点
s->data=x;
s->next=L->next;
L->next=s; //将新结点插入表中,L为头指针
scanf("%d",&x);
}
return L;
}
采用头插法建立单链表时,读入数据的顺序与生成的链表中的元素的顺序是相反的。每个结点插入的时间为O(1),设单链表长为n,则总时间复杂度为O(n)。
2.采用尾插法建立单链表
头插法建立单链表的算法虽然简单,但生成的链表中结点的次序和输入数据的顺序不一致。希望两者次序一致,则可采用尾插法。该方法将新结点插入到当前链表的表尾,为此必须增加一个尾指针r,使其始终指向当前链表的尾结点。
尾插法建立单链表的算法: