学习
前言
第三章线性表学习
一、线性表是什么?
线性表是一种常见的数据结构,它是由一组具有相同数据类型的元素按照线性顺序排列而成的数据集合。线性表中的元素之间存在一对一的关系,即除了第一个元素和最后一个元素之外,每个元素都有且只有一个直接前驱元素和一个直接后继元素。
线性表常见的操作包括:
- 插入元素:在指定位置插入一个新元素。
- 删除元素:删除指定位置的元素。
- 查找元素:根据元素的值或者位置查找元素。
- 修改元素:修改指定位置的元素的值。
- 遍历元素:按照一定的顺序访问线性表中的所有元素。
二、顺序存储结构
顺序存储结构是一种线性表的存储方式,它使用一段连续的存储空间来存储线性表的元素。在顺序存储结构中,线性表的元素在内存中的物理地址是连续的,元素之间的关系通过其在内存中的相对位置来表示。
顺序存储结构的实现通常使用数组来存储元素。数组是一种固定大小的数据结构,它可以在内存中分配一段连续的存储空间来存储元素。在顺序存储结构中,线性表的元素按照顺序依次存储在数组中,可以通过元素的下标来访问和操作元素。
顺序存储结构的特点包括:
- 随机访问:由于元素在内存中的物理地址是连续的,因此可以通过元素的下标直接访问元素,具有较高的访问效率。
- 存储效率高:顺序存储结构不需要额外的空间来存储指针,因此存储效率较高。
- 插入和删除操作效率低:由于顺序存储结构中的元素是连续存储的,插入和删除操作可能需要移动大量元素,因此效率较低。
顺序存储结构的线性表操作举例:删除操作
/* 初始条件:顺序线性表L已存在,1≤i≤ListLength(L) */
/* 操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减1 */
Status ListDelete(SqList *L,int i,ElemType *e)
{
int k;
if (L->length==0) /* 线性表为空 */
return ERROR;
if (i<1 || i>L->length) /* 删除位置不正确 */
return ERROR;
*e=L->data[i-1];
if (i<L->length) /* 如果删除不是最后位置 */
{
for(k=i;k<L->length;k++)/* 将删除位置后继元素前移 */
L->data[k-1]=L->data[k];
}
L->length--;
return OK;
}
三、链式存储结构
链式存储结构是一种线性表的存储方式,它使用一系列的节点来存储线性表的元素。每个节点包含了元素本身的值,以及指向下一个节点的指针。
在链式存储结构中,每个节点都是通过指针来连接的。节点中的指针指向下一个节点的地址,通过这种方式,整个线性表的元素可以按照任意顺序存储在内存中。
链式存储结构的特点包括:
- 动态分配内存:链式存储结构可以根据需要动态地分配内存空间,不需要预先确定存储空间的大小。
- 插入和删除操作效率高:由于链式存储结构中的节点通过指针连接,插入和删除操作只需要修改指针的指向,效率较高。
- 随机访问效率低:由于链式存储结构中的节点不是连续存储的,无法通过下标直接访问元素,需要从头节点开始遍历链表才能找到指定位置的元素,因此随机访问的效率较低。
1.单链表
单链表是一种常见的链式存储结构,也是最简单的链式存储结构之一。它由一系列的节点组成,每个节点包含了元素的值和指向下一个节点的指针。
单链表的特点包括:
- 每个节点包含了元素的值和指向下一个节点的指针。
- 链表的第一个节点称为头节点,最后一个节点的指针指向空值(NULL)。
- 链表中的节点在内存中不一定是连续存储的,它们通过指针连接在一起。
单链表操作举例:插入操作
/* 初始条件:链式线性表L已存在,1≤i≤ListLength(L), */
/* 操作结果:在L中第i个位置之前插入新的数据元素e,L的长度加1 */
Status ListInsert(LinkList *L,int i,ElemType e)
{
int j;
LinkList p,s;
p = *L;
j = 1;
while (p && j < i) /* 寻找第i个结点 */
{
p = p->next;
++j;
}
if (!p || j > i)
return ERROR; /* 第i个元素不存在 */
s = (LinkList)malloc(sizeof(Node)); /* 生成新结点(C语言标准函数) */
s->data = e;
s->next = p->next; /* 将p的后继结点赋值给s的后继 */
p->next = s; /* 将s赋值给p的后继 */
return OK;
}
2.循环链表
循环链表是一种特殊的链式存储结构,它与单链表的区别在于最后一个节点的指针不是指向空值(NULL),而是指向链表的头节点,形成一个环形结构。
循环链表的特点包括:
- 最后一个节点的指针指向头节点,形成一个闭环。
- 可以通过任意一个节点遍历整个链表。
3.双向链表
双向链表是一种链式存储结构,它与单链表的区别在于每个节点不仅包含指向下一个节点的指针,还包含指向前一个节点的指针。
双向链表的特点包括:
- 每个节点包含了元素的值、指向下一个节点的指针和指向前一个节点的指针。
- 链表的第一个节点称为头节点,最后一个节点称为尾节点。
- 可以通过任意一个节点遍历整个链表,可以从头节点或尾节点开始遍历。
4.静态链表
静态链表是一种使用数组实现的链式存储结构,它模拟了链表的特性,但是在内存中是连续存储的。
静态链表的特点包括:
- 使用数组来存储节点,每个节点包含元素的值和指向下一个节点的指针。
- 不像动态链表需要频繁的内存分配和释放,静态链表在创建时就分配好了固定大小的内存空间。
- 静态链表可以支持插入和删除操作,但是需要手动管理空闲节点和释放节点。
静态链表操作举例:插入操作
/* 在L中第i个元素之前插入新的数据元素e */
Status ListInsert(StaticLinkList L, int i, ElemType e)
{
int j, k, l;
k = MAXSIZE - 1; /* 注意k首先是最后一个元素的下标 */
if (i < 1 || i > ListLength(L) + 1)
return ERROR;
j = Malloc_SSL(L); /* 获得空闲分量的下标 */
if (j)
{
L[j].data = e; /* 将数据赋值给此分量的data */
for(l = 1; l <= i - 1; l++) /* 找到第i个元素之前的位置 */
k = L[k].cur;
L[j].cur = L[k].cur; /* 把第i个元素之前的cur赋值给新元素的cur */
L[k].cur = j; /* 把新元素的下标赋值给第i个元素之前元素的ur */
return OK;
}
return ERROR;
}
总结
这一周,主要学习了第三章的线性表,先学习了它的定义,线性表是零个或多个具有相同类型的数据元素的有限序列。之后学习了线性表的两大结构,先学的是比较容易的顺序存储结构,指的是用一段地址连续的存储单元依次存储线性表的数据元素。通常我们都是用数组来实现这一结构的。后来是重点,由顺序存储结构的插入和删除操作不方便,引出了链式存储结构。它具有不受固定的存储空间限制,可以比较快捷地插入和删除操作的特点。然后又分别了解链式存储结构的不同形式,如单链表、循环链表和双向链表,另外还学了若不使用指针如何处理链表结构的静态链表方法。
总的来说,刚刚线性表的内容,有点不知所措,能够大体看懂代码,但还无法独自完整的写出,还
需继续努力。加油!