2.2 线性表的顺序表示

本文介绍了顺序表的基本概念,包括定义、特点及其实现方式,并详细阐述了顺序表的插入、删除和查找三种基本操作的实现方法及其时间复杂度。

一、顺序表的定义

1.线性表的顺序存储又称顺序表。它是用一组地址连续的存储单元依次存储线性表中的数据元素,从而使得逻辑上相邻的两个元素在物理位置上也相邻。

2.线性表中元素的位序是从1开始的。

3.一维数组可以是静态分配的,也可以是动态分配的。在静态分配时,由于数组的大小和空间事先已经固定,一旦空间占满,再加入新的数据将会产生溢出,进而导致程序崩溃。而在动态分配时,存储数组的空间是在程序执行过程中通过动态存储分配语句分配的,一旦数据空间占满,就另外开辟一块更大的存储空间,用以替换原来的存储空间,从而达到扩充数组的目的。

4.假定线性表的元素类型为ElemType,则线性表的顺序存储类型描述为:
(1)
#define MaxSize 50 //定义线性表的最大长度
typedef struct
{
ElemType data[MaxSize]; //顺序表的元素
int length; //顺序表的当前长度
}SqList; //顺序表的类型定义

(2)
#define InitSize 100 //表长度的初始定义
typedef struct
{
ElemType *data; //指示动态分配数组的指针
int MaxSize,length; //数组的最大容量和当前个数
}SqList; //动态分配数组顺序表的类型定义

C的初始动态分配语句为:
L.data=(ElemType*)malloc(Sizeof(ElemType)*InitSize);

C++的初始动态分配语句为
L.data=new ElemType[InitSize];

5.顺序表最主要的特点是随机访问,即通过首地址和元素序号可在时间O(1)内找到指定的元素。顺序表的存储密度高,每个结点只存储数据元素。顺序表逻辑上相邻的元素物理上也相邻,所以插入和删除需要移动大量元素。

二、顺序表基本操作的实现

1.插入操作
在顺序表L的第i(1<=i<=L.length+1)个位置插入新元素e。若i的输入不合法,则返回false,表示插入失败;否则,将顺序表的第i个元素及其后的所有元素右移一个位置,腾出一个空位置插入新元素e,顺序表长度增加1,插入成功,返回true
bool ListInsert(SqList &L,int i,ElemType e)
{
if(i<=1||i>=L.length+1) //判断i的范围是否有效
return false;
if(L.length>MaxSize) //当前存储空间已满,不能插入
return false;
for(int j=L.length;j>=i;j–)//将第i个元素之后的元素后移
L.data[j]=L.data[j-1];
L.data[i-1]=e;//在位置i处放入e
L.length++;//线性表长度+1
return true;
}
最好情况:在表尾插入,元素不需要移动,时间复杂度为O(1)
最坏情况:在表首插入,所有元素都要移动,时间复杂度为O(n)
平均情况:平均移动次数为n/2,时间复杂发为O(n)

2.删除操作
删除顺序表L中第i(1<=i<=L.length)个位置的元素,若成功则返回true,并将被删除的元素引用变量e返回,否则返回false
bool ListDelete(SqList &L,int i,ElemType &e)
{
if(i<=1||i>=L.length+1) //判断i的范围是否有效
return false;
e=L.data[i-1]; //将被删除的元素赋值给e
for(int j=i;j<L.length;j++)//将第i个位置后的元素前移
L.data[j-1]=L.data[j];
L.length–;//线性表长度-1
}
最好情况:删除表尾元素,无需移动元素,时间复杂度为O(1)
最坏情况:删除表头元素,需要移动所有元素,时间复杂度为O(n)
平均情况:平均次数为(n-1)/2,时间复杂度围殴O(N)

3.按值查找(顺序查找)
在顺序表L中查找第一个元素值等于e的元素,并返回其位序
int LocateElem(SqList L,ElemType e)
{
int i;
for(i=0;i<L.length;i++)
if(L.data[i]==e)
return i+1;
return 0; //退出循环,说明查找失败
}
最好情况:查找的元素就在表头,比较一次,时间复杂度为O(1)
最坏情况:查找的元素在表尾或不存在,比较n次,时间复杂度为O(n)
平均情况:平均次数为(n+1)/2,时间复杂度为O(n)

<think>我们正在讨论线性表的类型定义、顺序表示和实现、链式表示和实现,以及一元多项式的表示和相加应用。根据用户提供的引用,我们可以知道线性表在存储多项式时的应用,以及两种存储结构(顺序和链式)在不同运算中的适用性。同时,用户希望了解线性表的定义、基本操作、特点和应用。 我将按照以下结构组织回答: 1. 线性表的类型定义 2. 顺序表示与实现 2.1 定义 2.2 基本操作(初始化、插入、删除、查找等) 2.3 特点 3. 链式表示与实现 3.1 定义(单链表、双向链表、循环链表等) 3.2 基本操作(创建、插入、删除、查找等) 3.3 特点 4. 线性表的应用:一元多项式的表示与相加(结合引用[1][2][3][4]) 4.1 一元多项式的表示顺序和链式) 4.2 一元多项式的相加(链式实现示例) 注意:在回答中,我们将使用LaTeX格式表示数学公式,代码块使用指定语言,并按照要求添加引用标识。 开始回答: </think>### 线性表的类型定义、表示与实现 #### 1. 线性表的类型定义 **定义**:线性表是由 $n$($n \geq 0$)个**相同数据类型**的元素构成的有限序列,记作: $$(a_1, a_2, \dots, a_n)$$ 其中 $a_i$ 是元素,$n$ 为表长。当 $n=0$ 时称为空表[^1]。 **逻辑特性**: - 存在唯一**首元素** $a_1$ 和**尾元素** $a_n$ - $a_i$ 的直接前驱是 $a_{i-1}$($i>1$) - $a_i$ 的直接后继是 $a_{i+1}$($i<n$) **抽象数据类型定义**(ADT): ```c ADT List { 数据对象:D = {a_i | a_i ∈ ElemType, i=1,2,...,n} 数据关系:R = {<a_{i-1}, a_i> | a_{i-1}, a_i ∈ D} 基本操作: InitList(&L) // 初始化 DestroyList(&L) // 销毁 ListInsert(&L, i, e) // 在位置i插入元素e ListDelete(&L, i, &e) // 删除位置i的元素 LocateElem(L, e) // 查找元素e的位置 ... } ``` --- ### 2. 顺序表示与实现 #### 定义 采用**连续存储空间**存放元素,逻辑上相邻的元素物理位置也相邻: $$ \text{Loc}(a_i) = \text{Loc}(a_1) + (i-1) \times c $$ 其中 $c$ 为元素大小[^1]。 **C语言实现**: ```c #define MAXSIZE 100 typedef struct { ElemType data[MAXSIZE]; // 静态分配 int length; // 当前长度 } SqList; ``` #### 基本操作 **插入操作**: ```c Status ListInsert(SqList &L, int i, ElemType e) { if (i < 1 || i > L.length+1) return ERROR; // 位置非法 if (L.length >= MAXSIZE) return ERROR; // 空间满 for (int j = L.length; j >= i; j--) // 元素后移 L.data[j] = L.data[j-1]; L.data[i-1] = e; L.length++; return OK; } ``` **时间复杂度**: - 最好 $O(1)$(尾部插入) - 最坏 $O(n)$(头部插入) - 平均 $O(n)$ **删除操作**: ```c Status ListDelete(SqList &L, int i, ElemType &e) { if (i < 1 || i > L.length) return ERROR; e = L.data[i-1]; for (int j = i; j < L.length; j++) // 元素前移 L.data[j-1] = L.data[j]; L.length--; return OK; } ``` **时间复杂度**:$O(n)$ #### 特点 | 优点 | 缺点 | |------|------| | 随机访问 $O(1)$ | 插入/删除效率低 $O(n)$ | | 存储密度高 | 需预估最大长度 | | 缓存友好 | 扩容代价高 | --- ### 3. 链式表示与实现 #### 定义 通过**指针**链接的节点序列,节点结构: ```c typedef struct LNode { ElemType data; // 数据域 struct LNode *next; // 指针域 } LNode, *LinkList; ``` #### 基本操作 **头插法创建链表**: ```c void CreateList_H(LinkList &L, int n) { L = (LinkList)malloc(sizeof(LNode)); L->next = NULL; // 创建头结点 for (int i = 0; i < n; i++) { LNode *p = (LNode*)malloc(sizeof(LNode)); scanf("%d", &p->data); p->next = L->next; // 新节点指向原首元节点 L->next = p; // 头结点指向新节点 } } ``` **指定位置插入**: ```c Status ListInsert(LinkList &L, int i, ElemType e) { LNode *p = L; int j = 0; while (p && j < i-1) { // 定位到第i-1个节点 p = p->next; j++; } if (!p || j > i-1) return ERROR; LNode *s = (LNode*)malloc(sizeof(LNode)); s->data = e; s->next = p->next; // 新节点指向原后继 p->next = s; // 原前驱指向新节点 return OK; } ``` **时间复杂度**:$O(n)$(查找)+ $O(1)$(插入) #### 特点 | 优点 | 缺点 | |------|------| | 动态内存分配 | 存储密度低 | | 插入/删除 $O(1)$ | 不支持随机访问 | | 无需预知规模 | 指针消耗额外空间 | --- ### 4. 一元多项式表示与相加应用 #### 表示方法 **链式存储结构**(解决指数差异大问题): ```c typedef struct PolyNode { float coef; // 系数 int expn; // 指数 struct PolyNode *next; } PolyNode, *Polynomial; ``` 示例多项式 $3x^5 + 2x^2 - 6$ 的存储: ```mermaid graph LR A[头结点] --> B[3|5] --> C[2|2] --> D[-6|0] --> NULL ``` #### 多项式相加算法 ```c void AddPolyn(Polynomial &Pa, Polynomial &Pb) { Polynomial p = Pa->next, q = Pb->next; Polynomial pre = Pa; // 指向p的前驱 while (p && q) { if (p->expn < q->expn) { // Pa节点指数小 pre = p; p = p->next; } else if (p->expn > q->expn) { // 插入Pb节点 Polynomial s = (Polynomial)malloc(sizeof(PolyNode)); *s = *q; // 复制节点 s->next = p; pre->next = s; pre = s; q = q->next; } else { // 指数相等 p->coef += q->coef; if (fabs(p->coef) < 1e-6) { // 系数和为0 pre->next = p->next; free(p); p = pre->next; } else { pre = p; p = p->next; } Polynomial tmp = q; q = q->next; free(tmp); } } if (q) pre->next = q; // 链接剩余项 free(Pb); } ``` **算法分析**: - **时间复杂度**:$O(m+n)$($m,n$ 为多项式项数) - **空间复杂度**:$O(1)$(原地合并) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值