数据结构:【学习笔记】02 线性结构——线性表

线性表

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 
#include 
/*十字链表的结构类型定义如下:*/
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; /*完成插入*/
        }
    }
}

你可能感兴趣的:(数据结构)