线性表
1 存储方法问题
实例:多项式f ( x ) 的表示。
方法一 顺序存储结构直接表示
数组各分量对应多项式的各项:
a【i】:项 x ^ i 的系数 ai 。
两个多项式相加:两个数组对应分量的相加。
缺点:表示多项式 x + x ^ 2000 时存在巨大的空间浪费。
方法二 顺序存储结构表示非零项
用结构数组(二维数组)表示:数组分量是由系数 ai 、指数 i 组成的结构,对应一个非零项。
注意:存储时需要将指数大小从小到大排序,方便之后的运算。
方法三 链表结构存储非零项
链表中每个结点存储多项式中的一个非零项,包括系数和指数两个数据域以及一个指针域
coef | expon | link |
---|
typedef struct PolyNode *Polynomial;
struct PolyNode {
int coef;
int expon;
Polynomial link;
};
2 什么是线性表
线性表(Linear List):由同类型数据元素构成有序序列的线性结构
- 表中元素个数称为线性表的长度
- 线性表没有元素时,称为空表
- 表起始位置称为表头,表结束位置称为表尾
3 线性表的顺序存储
基本结构如下:
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
int last;
};
struct LNode L;
List PtrL;
3.1 初始化:
List MakeEmpty()
{
List PtrL;
PtrL = (List)malloc(sizeof(struct LNode));
PtrL -> Last = -1;
return PtrL;
}
3.2 查找:
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;
}
3.3 插入:
void Insert(ElementType X, int i, List PtrL)
{
int j;
if (PtrL->Last == MAXSIZE - 1) {
printf('FULL');
return;
}
if (i<1 || i>PtrL->Last + 2) {
printf('No right');
return;
}
for (j = PtrL->Last;j >= i - 1;j--)
PtrL->Data[j + 1] = PtrL->Data[j];
PtrL->Data[i - 1] = X;
PtrL->Last++;
return;
}
3.4 删除:
void Delete(int i, List PtrL)
{
int j;
if (i<1 || i>PtrL->Last + 1) {
printf("The %d item(s) no exist.", i);
return;
}
for (j = i;j <= PtrL->Last;j++)
PtrL->Data[j - 1] = PtrL->Data[j];
PtrL->Last--;
return;
}
4 线性表的链式存储实现
基本结构如下:
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE];
List Next;
};
struct LNode L;
List PtrL;
4.1 求表长:
int Length(List PtrL)
{
List p = PtrL;
int j = 0;
while (p) {
p = p->Next;
j++;
}
return j;
}
4.2 查找:
(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;
}
(2)按值查找:
List Find(ElementType X, List PtrL)
{
List p = PtrL;
while (p != NULL && p->Data != X)
p = p->Next;
return p;
}
4.3 插入
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("Parameter i Error!");
return NULL;
}
else
{
s=(List)malloc(sizeof(struct LNode));
s->Data = X;
s->Next = p->Next;
p->Next = s;
return PtrL;
}
}
4.4 删除
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("The %d intersection no exist.", i - 1);
return NULL;
}
else if (p->Next == NULL) {
printf("The %d intersection no exist.", i);
return NULL;
}
else {
s = p->Next;
p->Next = s->Next;
free(s);
return PtrL;
}
}
5 广义表和多重链表
5.1 广义表
例子:如何表示二元多项式?
- 广义表是线性表的推广
- 对于线性表而言,n个元素都是基本的单元素
- 广义表中,这些元素不仅可以是单元素,也可以是另一个广义表
基本格式如下:
typedef struct GNode *GList;
struct GNode {
int Tag;
// 标志域:0表示结点是单元素;1表示结点是广义表。
union {
// 字表指针域SubList与单元素数据域Data复用,共用存储空间。
ElementType Data;
GList SubList;
}
URegion;
GList Next;
};
5.2 多重链表
- 多重链表中结点的指针域会有很多,如前面例子包含了Next和SubList两个指针域。
- 但包含两个指针域的链表并不一定是多重链表,比如在双向链表不是多重链表。
- 多重链表用途广泛,基本上数、图这样相对复杂的数据结构都可以采用多重链表的方式来存储。
实例:矩阵的表示。
若用二维数组表示的话,会有两个缺陷:
- 数组的大小需要事先知道。
- 对于稀疏矩阵会造成存储空间的浪费。
【分析】采用一种典型的多重链表——十字链表来存储稀疏矩阵
-
只存储矩阵非0元素项
结点的数据域:行坐标Row、列坐标Col、数值Value
-
每个结点通过两个指针域,把行列串起来
1、行指针(向右指针)Right
2、列指针(向下指针)Down
十字链表代码示例:
#include <malloc.h>
#include <stdio.h>
/*十字链表的结构类型定义如下:*/
typedef struct OLNode
{
int row,col; /*非零元素的行和列下标*/
int value;
struct OLNode *right; /*非零元素所在行表、列表的后继链域*/
struct OLNode *down;
} OLNode, *OLink;
typedef struct
{
OLink *row_head; /*行、列链表的头指针向量*/
OLink *col_head;
int m,n,len; /*稀疏矩阵的行数、列数、非零元素的个数*/
} CrossList;
/*建立稀疏矩阵的十字链表的算法*/
void CreateCrossList(CrossList *M)
{
int m, n, t, i, j, e;
OLNode* p;
OLNode* q;
/*采用十字链表存储结构,创建稀疏矩阵M*/
scanf("%d%d%d", &m,&n,&t); /*输入M的行数,列数和非零元素的个数*/
M->m=m;
M->n=n;
M->len=t;
if(!(M->row_head=(OLink *)malloc(m*sizeof(OLink))))
exit(OVERFLOW);
if(!(M->col_head=(OLink * )malloc(n*sizeof(OLink))))
exit(OVERFLOW);
/*初始化行、列,头指针指向量,各行、列链表为空的链表*/
for(int h=0; h<m+1; h++)
{
M->row_head[h] = NULL;
}
for(int t=0; t<n+1; t++)
{
M->col_head[t] = NULL;
}
for(scanf("%d%d%d", &i,&j,&e); e!=0; scanf("%d%d%d", &i,&j,&e))
{
if(!(p=(OLNode *)malloc(sizeof(OLNode))))
exit(OVERFLOW);
p->row=i;
p->col=j;
p->value=e; /*生成结点*/
if(M->row_head[i]==NULL)
M->row_head[i]=p;
p->right=NULL;
else
{
/*寻找行表中的插入位置*/
for(q=M->row_head[i]; q->right&&q->right->col<j; q=q->right); /*空循环体*/
p->right=q->right;
q->right=p; /*完成插入*/
}
if(M->col_head[j]==NULL)
M->col_head[j]=p;
p->down=NULL;
else
{
/*寻找列表中的插入位置*/
for(q=M->col_head[j]; q->down&&q->down->row<i; q=q->down); /*空循环体*/
p->down=q->down;
q->down=p; /*完成插入*/
}
}
}