1.线性表
1.1基本概念
多项式的表示
【例】一元多项式及其运算
一元多项式: f ( x ) = a 0 + a 1 x + . . . + a n − 1 x n − 1 + a n x n f(x)=a_0+a_1x+...+a_{n-1}x^{n-1}+a_nx^n f(x)=a0+a1x+...+an−1xn−1+anxn
主要运算: 多项式相加、相减、相乘等
【分析】如何表示多项式?
多项式的关键数据:
- 多项式项数 n n n
- 各项系数 a i a_i ai 及指数 i i i
方式一: 顺序存储结构直接表示
数组各分量对应多项式各项: a [ i ] a[i] a[i]:项 x i x^i xi 的系数 a i a_i ai
例如: f ( x ) = 4 x 5 − 3 x 2 + 1 f(x)=4x^5-3x^2+1 f(x)=4x5−3x2+1
表示成:
下标i | 0 | 1 | 2 | 3 | 4 | 5 | … |
---|---|---|---|---|---|---|---|
a [ i ] a[i] a[i] | 1 | 0 | -3 | 0 | 0 | 4 | … |
1 | − 3 x 2 -3x^2 −3x2 | 4 x 5 4x^5 4x5 |
两个多项式的相加: 两个数组对应分量相加
问题: 如何表示多项式 x + 3 x 2000 x+3x^{2000} x+3x2000 ?
该方法容易造成空间的浪费
方法二: 顺序存储结构表示非零项
每个非零项 a i x i a_ix^i aixi 涉及两个信息:系数 a i a_i ai 和指数 i i i
可以将一个多项式看成是一个 ( a i , i ) (a_i,i) (ai,i) 二元组的集合。
用结构数组表示: 数组分量是由系数 a i a^i ai 、指数 i i i 组成结构,对应一个非零项
例如: P 1 ( x ) = 9 x 12 + 15 x 8 + 3 x 2 P_1(x)=9x^{12}+15x^8+3x^2 P1(x)=9x12+15x8+3x2 和 P 2 ( x ) = 26 x 1 9 − 4 x 8 − 13 x 6 + 82 P_2(x)=26x^19-4x^8-13x^6+82 P2(x)=26x19−4x8−13x6+82
可以分别表示为:
下标 i i i | 0 | 1 | 2 | … |
---|---|---|---|---|
系数 a i a^i ai | 9 | 15 | 3 | - |
指数 i i i | 12 | 8 | 2 | - |
下标 i i i | 0 | 1 | 2 | 3 | … |
---|---|---|---|---|---|
系数 a i a^i ai | 26 | -4 | -13 | 82 | - |
指数 i i i | 19 | 8 | 6 | 0 | - |
要点:按指数大小有序存储!
相加过程:从头开始,比较两个多项式当前对应项的指数
下标 i i i | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|
P1: | (9,12) | (15,8) | (3,2) | |||
P2: | (26,19) | (-4,8) | (-13,6) | (82,0) | ||
P3: | (26,19) | (9,12) | (11,8) | (-13,6) | (3,2) | (82,0) |
P 3 ( x ) = 26 x 1 9 + 9 x 12 + 11 x 8 − 13 x 6 + 3 x 2 + 82 P_3(x)=26x^19+9x^{12}+11x^8-13x^6+3x^2+82 P3(x)=26x19+9x12+11x8−13x6+3x2+82
方法三: 链表结构存储非零项
链表中每个节点 储存多项式中的一个非零项 ,包括系数和指数 两个数据域以及一个指针域
coef (coefficients) | expon (exponent) | link |
---|
typedef struct PolyNode *Polynomial;
typedef struct PolyNode{
int coef;
int expon;
Polynomial link;
}
P1
→
\rightarrow
→ 9 | 12 |
→
\rightarrow
→ 15 | 8 |
→
\rightarrow
→ 9 | 12 | NULL
P2
→
\rightarrow
→ 26 | 19 |
→
\rightarrow
→ -4 | 8 |
→
\rightarrow
→ -13 | 6 |
→
\rightarrow
→ 80 | 0 | NULL
加法运算同上述方法
1.1.1什么是线性表
多项式表示问题的启示:
- 同一个问题可以有不同的表示(储存)方法
- 有一类共性问题:有序线性序列的组织和管理
“线性表(Linear List)”:由同类型数据元素 构成有序序列 的线性结构
- 表中元素个数称为线性表的长度
- 线性表没有元素时,称为空表
- 表起始位置称表头 ,表结束位置称表尾
1.1.2线性表的抽象数据类型描述
类型名称: 线性表(List)
数据对象集: 线性表时n( ≥ \geq ≥ 0)个元素构成的有序序列( a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an)
操作集: 线性表L ∈ \in ∈ List,整数i表示位置,元素X ∈ \in ∈ ElementType,线性表基本操作主要有:
List MakeEmpty()
:初始化一个空线性表L;ElemeneType FindKth(int K, List L)
:根据位序K,返回相应元素;int Find(ElementType X, List L)
:在线性表L中查找X的第一次出现位置;void Insert(ElementType X, int i, List L)
:在位序i前插入一个新元素X;void Delete(int i, List L)
:删除指定位序i的元素;int Length(List L)
:返回线性表L的长度n。
1.2线性表的顺序存储实现
利用数组的连续存储空间顺序存放 线性表的各元素
下标 i i i | 0 0 0 | 1 1 1 | … | i − 1 i-1 i−1 | i i i | … | n − 1 n-1 n−1 | … | MAXSIZE-1 |
---|---|---|---|---|---|---|---|---|---|
Data | a 1 a_1 a1 | a 2 a_2 a2 | … | a i a_i ai | a i + 1 a_{i+1} ai+1 | … | a n a_n an | … | - |
typedef struct{
ElementType Data[MAXSIZE];
int Last;
}List;
List L, *PtrL;
访问下标为
i
i
i 的元素: L.Data[i]
或PtrL->Data[i]
主要操作的实现
-
初始化(建立空的顺序表)
List *MakeEmpty() { List *PtrL; PtrL = (List *)malloc(sizeof(List) ); PtrL->Last = -1; return PtrL; }
-
查找
int Find(ElementType X, List *PtrL) { int i = 0; while(i <= PtrL->Last && PtrL->Data[i] != X) i++; if(i > PtrL->Last) return -1; //没找到返回-1 else return i; //找到后返回的是储存位置 }```
-
插入(第 i ( 1 ≤ i ≤ n + 1 ) i(1 \leq i \leq n+1 ) i(1≤i≤n+1) 个位置上插入一个值为X的新元素)
先移动,再插入
void Insert(ElementType X, int i, List *PtrL) { int j; if(PtrL->Last == MAXSIZE-1) //表空间已满,不能插入 { printf("表满"); return; } if(i < 1 || i > PtrL->Last+2) //检查插入位置的合法性 { printf("位置不合法"); return; } for(j = PtrL->Last; j >= i-1; j--) PtrL->Data[j+1] = PtrL->Data[j]; //向后移动 PtrL->Data[i-1] = X; //新元素插入 PtrL->Last++; //Last仍指向最后yun return; }
-
删除(删除表的第 i ( 1 ≤ i ≤ n + 1 ) i(1 \leq i \leq n+1 ) i(1≤i≤n+1)个位置上的元素)
void Delete(int i, List *PtrL) { int j; if(i < 1 || i > PtrL->Last+1) //检查空表及删除 { printf("不存在第%d个元素", i); return; } for(j = i; j <= PtrL->Last; j++) PtrL->Data[j-1] = PtrL->Data[j]; // 向前移动 PtrL->Last--; //Last仍指向最后元素 return; }
1.3线性表的链式存储实现(无头节点)
不要求逻辑上相邻的两个元素物理上也相邻;通过“链”建立起数据元素之间的逻辑关系;
插入、删除不需要移动数据元素,只需要修改“链”。
typedef struct Node
{
ElementType Data;
struct Node *Next;
}List;
List L, *PtrL;
主要操作
-
求表长
int Length(List *PtrL) { List *p = PtrL; //p指向表的第一个节点 int j = 0; while(p) { p = p->Next; j++; //当前p指向的是第j个节点 } return j; }
-
查找
-
按序号查找:FindKth;
List *FindKth(int K, List *PtrL) { List *p = PtrL; int i = 1; while(p != NULL && i < K) { p = p->Next; i++; } if(i == K) return p; //找到第K个,返回指针 else return NULL; //否则返回空 }
-
按值查找:Find
List *Find(ElementType X, List *PtrL) { List *p = PtrL; while(p != NULL && p->Data != X) p = p->Next; return p; }
-
-
插入(第 i − 1 ( 1 ≤ i ≤ n + 1 ) i-1(1 \leq i \leq n+1 ) i−1(1≤i≤n+1) 个节点后插入一个值为X的新元素)
- 先构造一个新节点,用 s s s 指向;
- 再找到链表的第 i − 1 i-1 i−1 个节点,用 p p p 指向;
- 然后修改指针,插入节点( p p p 之后插入的新节点是 s s s )
List *Insert(ElementType X, int i, List *PtrL)
{
List *p, *s;
if(i == 1) //新节点插入在表头
{
s = (List *)malloc(sizeof(List)); //申请、填装节点
s->Data = X;
s->Next = PtrL;
return s; //返回新表头指针
}
p = FindKth(i-1, PtrL); //查找第i-1个节点
if(p == NULL) //第i-1个不存在,不能插入
{
printf("参数i错");
return NULL;
}
else
{
s = (List *)malloc(sizeof(List)); //申请、填装节点
s->Data = X;
s->Next = p->Next; //新节点插入在第i-1个节点的后面
p->Next = s;
return PtrL;
}
}
-
删除(删除链表的第 i ( 1 ≤ i ≤ n ) i(1 \leq i \leq n ) i(1≤i≤n)个位置上的节点)
- 先找到链表的第 i − 1 i-1 i−1 个节点,用 p p p 所指节点;
- 再用指针 s s s 所指向要被删除的节点( p p p 的下一个节点);
- 然后修改指针,删除 s s s 所指节点;
- 最后释放 s s s 所指节点的空间;
List *Delete(int i, List *PtrL) { List *p, *s; if(i == 1) //若要删除的是表的第一个节点 { s = PtrL; //s指向第1个节点 if(PtrL != NULL) PtrL = PtrL->Next; //从链表中删除 else return NULL; free(s); //释放被删除节点 return PtrL; } p = FindKth(i-1, PtrL); //查找第i-1个节点 if(p == NULL) { printf("第%d个节点不存在", i-1); return NULL; } else if(p->Next == NULL) { printf("第%d个节点不存在", i); return NULL; } else { s = p->Next; //s指向第i个节点 p->Next = s->Next; //从链表中删除 free(s); //释放被删除节点 return PtrL; } }