数据结构-线性表-顺序表01

线性表

目录

2.1 线性表的基本概念

2.2 顺序表

2.3 单链表和循环单链表

2.4 双链表****和循环双链表

2.5 线性表的应用

2.1 线性表基本概念

1.认识线性表

线性表(Linear List)是计算机科学中的一种数据结构,用于存储有限数量的元素,并且这些元素具有线性关系,即每个元素除了第一个和最后一个之外,都有一个前驱和一个后继。线性表的元素之间具有明确的顺序关系,可以通过其位置进行访问和操作。

有序性:线性表中的元素按照一定的顺序排列,每个元素都有确定的位置。

唯一性:线性表中每个元素都有唯一的前驱后继除了第一个元素没有前驱,最后一个元素没有后继)。

长度有限线性表中的元素个数是有限的,可以为空表(长度为零)。

双向链表规则

顺序存储结构:用一组地址连续的存储单元依次存储线性表中的元素,例如数组。顺序存储结构的优点是支持随机访问(通过下标访问),缺点是在插入和删除元素时需要大量的移动操作。

链式存储结构:用一组任意的存储单元存储线性表的元素,并通过指针链接这些存储单元,例如链表。链式存储结构的优点是插入和删除操作较为高效,但访问速度较慢(需要从头遍历)。

2.线性表定义

1,线性表由n(n>=0)个相同类型的数据元素组成的有限序列

有序性

2.当n=0时为空表 记为() Φ

3.线性表的表示

有序性

0c3803f4fdf75b4424564fdf688ece46

4.线性表特殊

n>1 只有唯一的开始元素和终端元素

唯一性

5.标号序

线性表每个元素都有序号( 1 2 3 4 5)逻辑上 程序上从0开始-同时允许存储多个元素

3.线性表实现和运算

思路构造为:单链表

链表基础代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 定义链表节点类
class ListNode {
int value; // 节点存储的数据
ListNode next; // 指向下一个节点的指针

// 构造函数
ListNode(int value) {
this.value = value;
this.next = null;
}
}

// 定义链表类
class LinkedList {
private ListNode head; // 链表头指针

// 构造函数,初始化链表为空
public LinkedList() {
this.head = null;
}

// 插入节点的方法
public void insert(int value) {
// 插入新节点的逻辑 头插 记录old指针 新头+4指向old指针 尾插 尾next指向新开辟的节点地址 中间插 前链表+4->指向插入地址-插入地址+4指向下一个地址
}

// 删除节点的方法
public void delete(int value) {
// 删除节点的逻辑-前链表指针指向删除节点地址+4的地址-即可删除-本地还需delete -头删:直接删除-新头指针指向old指针+4的地址 尾删-链表-1遍历到第2个链接位置 +4位置=null;
}

// 查找节点的方法
public ListNode find(int value) {
// 查找节点的逻辑->遍历头指针+4的地址就是下个链表地址
return null;
}

// 打印链表的方法
public void printList() {
// 遍历并打印链表的逻辑-自写迭代器
}
}

线性表基本运算方法

da15cc5e809c8c28b188b72abb581438

fbe2b89d6443062cd08447d07620a599

初始化 InitList(L)

  • 逻辑:创建一个空的线性表 L,将其长度设为 0,或者创建一个数据结构(例如数组或链表)来表示空表。

销毁线性表 DestroyList(L)

  • 逻辑:释放线性表 L 所占的内存空间,将表设置为空,防止内存泄漏。
  • 迭代器销毁吗?一个个mc

求线性表的长度 GetLength(L)**

  • 逻辑:返回线性表 L 的当前长度(即线性表中元素的数量)。
  • 还是迭代-只有next有指向就++-直到没指向

求线性表中第 i 个元素 GetElem(L, i, e)**

  • 逻辑:检查位置 i 是否有效(在范围内),如果有效,返回位置 i 处的元素 e;否则,返回一个错误或特殊值。
  • 从头next尾 -找到i就返回

按值查找 Locate(L, x)

  • 逻辑:从线性表 L 的头开始,依次遍历每个元素,判断其值是否等于 x。如果找到,返回元素的位置索引;如果没有找到,返回一个表示未找到的特殊值(例如 -1)。
  • 从头next尾

插入元素 InsElem(L, x, i)**

  • 逻辑:首先检查插入位置 i 是否有效(例如是否在当前表的长度范围内)。然后从最后一个元素开始向后移动元素,腾出位置 i,最后在位置 i 插入新元素 x,并将线性表的长度加 1。
  • 头插 尾插 中间插(上面代码思路-未考虑长度)

删除元素 DelElem(L, i)

  • 逻辑:检查要删除的位置 i 是否有效。如果有效,从位置 i+1 开始的每个元素向前移动一位,覆盖位置 i 的元素。最后,减少线性表的长度。
  • next遍历索引

输出元素值 DispList(L)

  • 逻辑:从线性表 L 的头开始,依次遍历每个元素,将其值按顺序打印或存储

  • netx到尾部-迭代器写法

List->线性表

利用线性表List的基本运算,设计一个由线性表A和B中的公共元素产生线性表C的算法

a44dd445a0470ae167ed779690fcbd4c

2.2 顺序表

bb24d731f11ddcce85e4836fbc183460

ps:纳闷了一下-以为ai归纳错了-把顺序结构也包含在线性表中了

顺序表的定义

顺序表是在计算机内存中以数组的形式保存的线性表,是指用一组地址连续的存储单元依次存储数据元素的线性结构,使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系。

1
2
3
4
5
6
7
#define MaxSize 100
typedef int ElemType; //假设顺序表中所有元素为int类型
typedef struct
{ ElemType data[MaxSize]; //存放顺序表的元素-初始大小
int length; //顺序表的实际长度
} SqList; //顺序表类型

定义了数组长度为100的 int类型的数据

1
2
3
4
5
SqList list;   // 定义一个顺序表
list.length = 0; // 初始化长度为 0
list.data[0] = 10; // 插入第一个元素
list.length++; // 长度增加

724b39523239a1da419d0f99ca38b84d

**ArrayList**:适合大部分顺序表场景,动态数组实现,随机访问高效。

**Vector**:线程安全的动态数组,适合多线程环境,但性能略差。

**LinkedList**:双向链表,适合频繁插入和删除操作,但随机访问效率较低。

**CopyOnWriteArrayList**:线程安全,适合读多写少的场景。

**Arrays.asList()**:固定大小的顺序表,不能动态调整大小。

顺序表的基本运算

1.初始化线性表运算算法

设置初始长度-存储个数

1
2
3
4
5
6
void InitList(SqList &L) //引用修改
//由于L要回传给实参,所以用引用类型
{
  L.length=0;
}

2.销毁线性表运算算法

 L若在栈则return销毁 –也就是变量的生命周期

3.线性表长度运算算法
1
2
3
4
5
int GetLength(SqList L)
{
  return L.length;
}

4.求线性表中第i个元素运算算法
1
2
3
4
5
6
7
8
9
10
11
在逻辑序号i无效时返回特殊值0(假),有效时返回1(真),并用引用型形参e返回第i个元素的值。

int GetElem(SqList L,int i,ElemType &e)
{ if (i<1 || i>L.length) //无效的i值返回0 判断长度和下标合法性
return 0;
else
{ e=L.data[i-1]; //取元素值并返回1
return 1;
}
}

ElemType &e-取引用类型0类型是T泛型-这里没指定而且

5.按值查找运算算法
1
2
3
4
5
6
7
8
9
10
在顺序表L找第一个值为x的元素,找到后返回其逻辑序号,否则返回0(由于线性表的逻辑序号从1开始,这里用0表示没有找到值为x的元素)。
int Locate(SqList L,ElemType x)
{ int i=0;
while (i<L.length && L.data[i]!=x)
i++; //查找值为x的第1个元素,查找范围为0~L.length-1
if (i>=L.length) return(0); //未找到返回0
else return(i+1); //找到后返回其逻辑序号
}


逻辑序号就是下标+1

6.插入元素运算法
1
2
3
4
将新元素x插入到顺序表L中逻辑序号为i的位置(如果插入成功,元素x成为线性表的第i个元素)。
i无效时返回0(表示插入失败)。
有效时将L.data[i-1..L.length-1]后移一个位置,在L.data[i-1]处插入x,顺序表长度增1,并返回1(表示插入成功。

7759631b5998f2d56609e561e79b99d8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int InsElem(SqList &L,ElemType x,int i)
{ int j;
if (i<1 || i>L.length+1) //无效的参数i
return 0;
for (j=L.length;j>i;j--) //将位置为i的结点及之后的结点后移
{
L.data[j]=L.data[j-1];
}


L.data[i-1]=x; //在位置i处放入x
L.length++; //线性表长度增1
return 1;
}

j-i 是逻辑位置-下标+1所想

1
2
3
i=n+1时(插入尾元素),移动次数为0,呈现最好的情况。
i=1时(插入第一个元素),移动次数为n,呈现最坏的情况。

n是最大下标

平均情况分析

32db9894cf39150fb84a0ee2cefe595d

回头看看这个公式的计算方法

1
插入算法的主要时间花费在元素移动上,所以算法InsElem()的平均时间复杂度为O(n)。
7.删除元素运算算法
1
2
3
4
5
删除顺序表L中逻辑序号为i的元素。
i无效时返回0(表示删除失败)。
有效时将L.data[i..length-1]前移一个位置,顺序表长度减1,并返回1(表示删除成功。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int DelElem(SqList &L,int i)
{ int j;
if(i<1 || i>L.length)
return 0;


for(j=i,j<L.length;j++) //将位置为i的结点之后的结点前移

{
L.data[j-1]=L.data[j];
}
L.length--; //线性表长度减1
return 1;

}
1
2
3
4
5
i=n时(删除尾元素),移动次数为0,呈现最好的情况。
i=1时(删除第一个元素),移动次数为n-1,呈现最坏的情况。

删除算法的主要时间花费在元素移动上,所以算法DelElem()的平均时间复杂度为O(n)。

c419faf1b6160678f0145ea2ec2804cc

8.输出元素值运算算法

迭代器写法

1
2
3
4
5
6
7
void DispList(SqList L)
{ int i;
for (i=0;i<L.length;i++)
printf("%d ",L.data[i]);
printf("\n");
}

9.顺序表测试

将顺序表类型声明及其基本运算函数存放在*SqList.cpp文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "SqList.cpp"	     	//包括前面的顺序表基本运算函数
void main()
{ int i; ElemType e;
SqList L; //定义一个顺序表L
InitList(L); //初始化顺序表L
InsElem(L,1,1); //插入元素1
InsElem(L,3,2); //插入元素3
InsElem(L,1,3); //插入元素1
InsElem(L,5,4); //插入元素5
InsElem(L,4,5); //插入元素4
InsElem(L,2,6); //插入元素2
printf("线性表:");DispList(L);
printf("长度:%d\n",GetLength(L));
i=3; GetElem(L,i,e);
printf("第%d个元素:%d\n",i,e);
e=1;
printf("元素%d是第%d个元素\n",e,Locate(L,e));
i=4; printf("删除第%d个元素\n",i);
DelElem(L,i);
printf("线性表:");DispList(L);
DestroyList(L);
}

1
2
3
4
5
6
7
#define MaxSize 100
typedef int ElemType; //假设顺序表中所有元素为int类型
typedef struct
{ ElemType data[MaxSize]; //存放顺序表的元素-初始大小
int length; //顺序表的实际长度
} SqList; //顺序表类型

10.数组值创建顺序表
1
2
3
4
5
6
7
8
9
10
11
假设给定一个含有n个元素的数组a,由它来创建顺序表。

void CreateList(SqList &L,ElemType a[],int n)
{ int i,k=0; //k累计顺序表L中的元素个数
for (i=0;i<n;i++)
{ L.data[k]=a[i]; //向L中添加一个元素
k++; //L中元素个数增1
}
L.length=k; //设置L的长度
}

2.2.3 顺序表的算法设计示例

ps:上数据结构课的时候观看案例

1.基于顺序表基本操作的算法设计

这类算法设计中包括顺序表元素的查找、插入和删除等

2.3
2.4
2.5
2.基于整体建表的算法设计
1
2
这类算法设计中需要根据条件产生新的结果顺序表。

2.6
2.7
3.有序顺序表的二路归并算法
1
2
3
4
5
有序表是指按元素值递增或者递减排列的线性表。
有序顺序表是有序表的顺序存储结构。也可以采用链式存储结构。
对于有序表可以利用其元素的有序性提高相关算法的效率。
二路归并就是有序表的一种经典算法。

2.8
2.9
2.10

数据结构-线性表-顺序表01
http://example.com/2024/09/18/数据结构线性表(顺序表0)/
作者
John Doe
发布于
2024年9月18日
许可协议