2.1 线性表及其表现
一、什么是线性表
1. 一元多项式的表示
方法1:顺序存储结构直接表示 —— 适用于多项式中每一项的指数较小的情况
用一维数组的各分量表示多项式各项,即数组元素a[i] 表示多项式中项
x
i
x^i
xi的系数
a
i
a_i
ai?;两个多项式相加,就是两个数组对应的分量相加
例1 ,表示
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] | 1 | 0 | -3 | 0 | 0 | 4 | ... |
方法2:顺序存储结构表示非零项
用二维数组的各分量表示多项式各项,即数组元素a[i][j] 中,下标i 不一定表示多项式中第i+1 项,a[i][0] 表示多项式系数
a
i
a^i
ai,a[i][1] 表示多项式中项
x
i
x^i
xi的指数i 的值。这样,每个数组元素a[i][j] 指向非零项。这样,每一个多项式可以看成是一个
(
a
i
,
i
)
(a_i,i)
(ai?,i)二元组的集合。
在该法中,最号按照指数大小有序存储。
例2 ,表示
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
19
?
4
x
8
?
13
x
6
+
82
P_2(x)=26x^{19}-4x^8-13x^6+82
P2?(x)=26x19?4x8?13x6+82
使用多行2列的二维数组表示,如下
P1(x)的表示 | 下标i | 0 | 1 | 2 | ... | 系数a^i | 9 | 15 | 3 | ... | 指数 | 12 | 8 | 2 | ... |
P2(x)的表示 | 下标i | 0 | 1 | 2 | 3 | ... | 系数a^i | 26 | -4 | -13 | 82 | ... | 指数 | 19 | 8 | 6 | 0 | ... |
方法3:链表结构存储非零项
链表中的每一个结点存储多项式中的一个非零项,包括系数和指数两个数据域以及一个指针域。 在例2 中,可以声明链表
struct PolyNode {
int coef;
int expon;
Polynomial link;
}
typedef struct PolyNode *Polynomial;
2. 表示一元多项式的启示
- 同一问题可以有不同的表示和储存方法
- 有序线性序列可以用线性表
3. 线性表:由同类型数据元素构成有序序列的线性结构
- 线性表的长度:线性表中元素个数
- 空表:线性表没有元素
- 表头:线性表起始位置
- 表尾:线性表结束位置
4. 线性表的抽象数据类型描述
- 类型名称:线性表
- 数据对象集:线性表是
n 个元素构成的有序序列(
a
1
,
a
2
,
.
.
.
,
a
n
a_1,a_2,...,a_n
a1?,a2?,...,an?) - 操作集:线性表
L 用List 表示,整数i 表示位置,元素x 用ElementType 表示 - 线性表的基本操作:
List MakeEmpty ();
ElementType FindKth (int k, List L);
int Find (ElementType X, List L);
void Insert (ElementType X, int i, List L);
void Delete (int i, List L);
int Length (List L);
5. 线性表的顺序存储:可以利用数组的连续存储空间顺序存放线性表的各元素
-
初始化(建立空的顺序表) List MakeEmpty() {
List PtrL;
PtrL = (List )malloc( sizeof(struct LNode));
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;
} else {
return i;
}
}
复杂度:平均比较次数为
(
n
+
1
)
/
2
(n+1)/2
(n+1)/2,平均时间性能为
O
(
n
)
O(n)
O(n) 运气好,线性表中第一个元素是所查找的元素,比较次数是1 ;运气好,线性表中最后一个元素是所查找的元素,比较次数是n 。
-
插入元素(在索引号为i 的位置上插入一个值为X 的新元素)
void Insert(ElementType X, int i, List PtrL) {
int j;
if (PtrL->Last == MAXSIZE-1) {
printf("线性表已满\n");
return;
}
if (i < 1 || i > PtrL->Last + 2) {
printf("插入位置不合法\n");
return;
}
for (j = PtrL->Last; j >= i-1; j--) {
PtrL->Data[j+1] = PtrL->Data[j];
}
PtrL->Data[i-1] = X;
PtrL->Last++;
return;
}
复杂度:平均移动次数为
n
/
2
n/2
n/2,平均时间性能为
O
(
n
)
O(n)
O(n),主要由for 循环决定
-
删除第i 个元素
a
i
a_i
ai?
void Delete(int i, List PtrL) {
int j;
if (i < 1 || i > PtrL->Last + 1) {
printf("不存在第%d个元素\n");
return;
}
for (j = i; j <= PtrL->Last; j++) {
PtrL->Data[j-1] = PtrL->Data[j];
}
PtrL->Last--;
return;
}
复杂度:平均移动次数为
(
n
?
1
)
/
2
(n-1)/2
(n?1)/2,平均时间性能为
O
(
n
)
O(n)
O(n)
6. 线性表的链式存储实现
- 该存储方式只要求两个元素在逻辑上相邻,而不要求在物理上相邻
- 插入、删除元素不需要移动数据元素,秩序奥修改“链”
- 数据结构:
struct LNode {
ElementType Data;
List Next;
};
typedef struct LNode* List;
struct LNode L;
List PtrL;
-
求单向链表长
int Length(List PtrL) {
List p = PtrL;
int j = 0;
while (p) {
p = p->Next;
j++;
}
return j;
}
复杂度:时间性能为
O
(
n
)
O(n)
O(n)
-
查找元素 (1) 按序号查找
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;
} else {
return NULL;
}
}
复杂度:时间性能为
O
(
n
)
O(n)
O(n)
(2) 按值查找
List Find(ElementType X, List PtrL) {
List p = PtrL;
while (p != NULL && p->Data != X) {
p = p->Next;
}
return p;
}
复杂度:时间性能为
O
(
n
)
O(n)
O(n)
-
插入元素(在第i-1 个结点后插入一个值为X 的新结点) 思路:
- 先构造一个新结点,用
s 指向; - 再找到链表的第
i-1 个结点,用p 指向; - 然后修改指针,在
p 指向的结点后插入新结点
List Insert(ElementType X, int i, List PtrL) {
List p, s;
if (i == 1) {
s = (List)malloc(sizeof (struct LNode));
s->Data = X;
s->Next = PtrL;
return s;
}
p = FindKth(i-1, PtrL);
if (p == NULL) {
printf("参数i错误\n");
return NULL;
} else {
s = (List)malloc(sizeof (struct LNode));
s->Data = X;
s->Next = P->Next;
p->Next = s;
return PtrL;
}
}
-
删除元素(删除旧链表的第i 个位置上的结点) 思路:
- 先找到链表的第
i-1 个结点,用p 指向; - 再用指针
s 指向要被删除的结点,即p 指向的结点的下一个结点; - 修改指针,使
p 指向的结点指向指针s 指向的结点的下一个结点; - 最后释放
s 指向的结点的空间。
List Delete(int i, List PtrL) {
List p, s;
if (i == 1) {
s = PtrL;
if (PtrL != NULL) {
PtrL = PtrL->Next;
} else {
return NULL;
}
free(s);
return PtrL;
}
p = FindKth(i-1, PtrL);
if (p == NULL) {
printf("第%d个结点不存在", i-1);
return NULL;
} else if (p->Next == NULL) {
printf("第%d个结点不存在", i);
return NULL;
} else {
s = p->Next;
p->Next = s->Next;
free(s);
return PtrL;
}
}
复杂度:平均时间性能为
n
/
2
n/2
n/2
|