数据结构——数组和广义表

一、数组

1.ADT

n个相同类型的数据元素构成的有限序列。每个数据元素成为一个数组元素,每个元素在n给线性关系中的序号成为该元素的下标,下标的取值范围称为数组的

N维数组中的每个元素都受N个线性关系的约束

  • 初始化操作 InitArray(&A,n,bound1,…,boundn)
  • 销毁操作     DestroyArray(&A)
  • 读元素操作 Value(A,&e,index1,…,indexn)
  • 写元素操作 Assign(&A,e,index1,…,indexn)

2.数组的存储结构与寻址

(1)一维数组

设具有M个元素的一维数组的下标范围为闭区间 [0, M-1],每个数组元素占用 L 个存储单元。

ai 的存储地址:Loc( ai )=Loc(a0)+i×L

(2)二维数组

逻辑上是二维的,存储是一维的,有两种映射方式

按行优先:先行后列,先存储行号较小的元素,行号相同者先存储列号较小的元素。

Loc(aij) = Loc(a00)+( N×i+j )×L

按列优先:先列后行,先存储列号较小的元素,列号相同者先存储行号较小的元素。

Loc(aij) = Loc(a00)+( N×j+i )×L

(3)n维数组

Loc( j1, j2, …, jn )= Loc(0, 0, …, 0) + ( b2×b3×... ×bn×j1+ b3×...×bn×j2+ ...+ bn×jn-1 + jn ) L

= Loc(0, 0, …, 0) +   ∑ci ji

cn=L,ci-1 =bi×ci,1< i ≤ n。

二、矩阵的压缩存储

1.特殊矩阵

(1)对称矩阵

用一维数组,按行优先存储下三角元素。

$$ k=\left\{ \begin{aligned} \frac{i(i-1)}{2}+j-1,i\geq j\\\frac{j(j-1)}{2}+i-1,i< j \end{aligned} \right.

(2)下三角矩阵

$$ k=\left\{ \begin{aligned} \frac{i(i-1)}{2}+j-1,i\geq j\\\frac{n(n+1)}{2},i< j \end{aligned} \right.

(3)上三角矩阵

$$ k=\left\{ \begin{array}{rcl} \frac{(i-1)(2n-i+2)}{2}+j-i,i\leq j\\\\\frac{n(n+1)}{2},i> j \end{array} \right.

2.稀疏矩阵

假设 m 行 n 列的矩阵,其中非零元素(t 个)比例小于5%的矩阵为稀疏矩阵。

即,稀疏因子\delta \leq 0.05的矩阵为稀疏矩阵。

  • 三元组顺序表
  • 行逻辑链接顺序表
  • 十字链表

 (1)三元组(行, 列, 值)

 #define MAXSIZE 12500 
  typedef struct {
        int   i,j;               // 非零元的行下标和列下标
        ElemType  e;     // 非零元值
  } Triple;
  typedef struct {
       Triple data [ MAXSIZE+1 ];  
                                   // 用于存储三元组表, data[0]未用
        int   mu,nu,tu;  // 行数、列数和非零元个数
  } TSMatrix;

(2)行逻辑链接顺序表

#define MAXSIZE 12500 
#define  MAXSMN  500
  typedef struct {
        int   i,j;               // 非零元的行下标和列下标
        ElemType  e;     // 非零元值
  } Triple;
   typedef struct {
      Triple  data[ MAXSIZE+1 ]; 
      int  rpos[MAXMN+1];
      // 每行第一个元素的位置表
      int  mu, nu, tu;              
   } RLSMatrix;  

 (3)十字链表

typedef struct OLNode {
    int  row, col;      // 非零元的行下标和列下标
    ElemType  e;     // 非零元值
    struct  OLNode * right, * down
} OLNode, *OLink;
typedef struct {
    OLink *rhead,*chead; // 行/列表头指针数组
    int   mu, nu, tu;  // 行数、列数和非零元个数
} CrossList;

3.应用

(1)矩阵的快速转置算法

#define MAXSIZE 12500
typedef struct {
	int   i, j;               // 非零元的行下标和列下标
	int  e;     // 非零元值
} Triple;
typedef struct {
	Triple data[MAXSIZE + 1];
	// 用于存储三元组表, data[0]未用
	int   mu, nu, tu;  // 行数、列数和非零元个数
} TSMatrix;

bool FastTransMatrix(TSMatrix M, TSMatrix &T) {
	T.mu = M.nu;
	T.nu = M.mu;
	T.tu = M.tu;
	if (T.tu) {
		int num[MAXSIZE];	//存储M第 col 列非零元个数
		int cpos[MAXSIZE];	//存储M第 col 列第一个非零元在T.data 中的位置
		for (int col = 1; col <= M.nu; col++) {
			num[col] = 0;
		}
		for (int t = 1; t < T.tu; t++) {
			num[M.data[t].j]++;
		}
		cpos[1] = 1;
		for (int col = 2; col <= M.nu; col++) {
			cpos[col] = cpos[col - 1] + num[col - 1];
		}
		for (int t = 0; t < T.tu; t++) {
			int col = M.data[t].j;
			int pos = cpos[col];
			T.data[pos].i = M.data[t].j;
			T.data[pos].j = M.data[t].i;
			T.data[pos].e = M.data[t].e;
			cpos[col]++;
		}
		//时间复杂度O(nu+tu)
	}
	return true;
}

(2)稀疏矩阵的乘法

#define MAXSIZE 12500
#define MAXMN 500
typedef struct {
	int   i, j;               // 非零元的行下标和列下标
	int  e;     // 非零元值
} Triple;
typedef struct {
	Triple data[MAXSIZE + 1];
	int  rpos[MAXMN + 1];
	// 每行第一个元素的位置表
	int   mu, nu, tu;  // 行数、列数和非零元个数
} RTSMatrix;

bool MatrixMultiplication(RTSMatrix M, RTSMatrix N, RTSMatrix &A) {
	if (M.nu != N.mu) return false;
	A.mu = M.mu;
	A.nu = N.nu;
	A.tu = 0;
	if (M.tu*N.tu != 0) {
		int temp[MAXMN];
		for (int rowM = 1; rowM <= M.mu; rowM++) {
			for (int colM = 1; colM <= M.nu; colM++) {
				temp[colM] = 0;		//清0
			}
			A.rpos[rowM] = A.tu + 1;
			int nextrposM;		//M矩阵的元素的下一行非零元素在顺序表中的位置
			if (rowM < M.mu) {
				nextrposM = M.rpos[rowM + 1];
			}
			else {
				nextrposM = M.tu + 1;
			}
			//遍历M中第row行的所有元素
			for (int rposM = M.rpos[rowM]; rposM < nextrposM; rposM++) {
				int rowN = M.data[rposM].j;
				int nextrposN;
				if (rowN < N.mu) {
					nextrposN = N.rpos[rowN + 1];
				}
				else {
					nextrposN = N.tu + 1;
				}
				int rposN;
				//遍历N中第col行的所有元素,一次计算一行
				for (rposN = N.rpos[rowN]; rposN < nextrposN; rposN++) {
					int col = N.data[rposN].j;
					temp[col] += M.data[rposM].e*N.data[rposN].e;
				}
			}
			for (int col = 1; col <= A.nu; col++) {
				if (temp[col] != 0) {
					A.tu++;
					if (A.tu > MAXSIZE) {
						return false;
					}
					A.data[A.tu] = { rowM,col,temp[col] };
				}
			}
		}
	}
	return true;
}

三、广义表

1.ADT

广义表(lists)是一种不同构的线性结构, LS = ( a1,  a2, ... ,an)其中ai或为原子(atom) 或为广义表。

广义表是递归定义

广义表中的元素既可以是单个元素(原子atom),也可以是广义表(子表sublist),当每个元素均为原子且类型相同时,就是线性表。

表头:LS的第一个元素称为表头

表尾:其余元素组成的表称为LS的表尾

表长:最外层包含元素个数

深度:所含括号的重数。原子的深度为 0,空表的深度为 1。

InitGList(&L);

DestroyGList(&L);

CreateGList(&L, S);

CopyGList(&T, L);

GListLength(L);

GListDepth(L);

GListEmpty(L);

GetHead(L);

GetTail(L);

InsertFirst_GL(&L, e);

DeleteFirst_GL(&L, &e);

Traverse_GL(L, Visit());

typedef struct Node
{
	int tag;//0表示原子,1表示表  
	char atom;
	struct Node *hp;//指向子表  
	struct Node *tp;//指向下一个节点  
}GLNode;
GLNode* CreatList(char* &str)
{
	Node *head = new Node;
	GLNode* p = head;
	p->hp = NULL;
	p->tp = NULL;
	p->atom = '\0';
	p->tag = -1;
	++str;
	while (*str)
	{
		if (*str >= 'a'&&*str <= 'z')
		{
			p->tag = 0;
			p->atom = *str;
			p->tp = new Node;
			p = p->tp;
			p->hp = NULL;
			p->tp = NULL;
			p->atom = '\0';
			p->tag = -1;
			++str;
		}
		else if (*str == '(')
		{
			p->tag = 1;
			p->hp = new Node;
			p->hp = CreatList(str);
			p->tp = new Node;
			p = p->tp;
			p->hp = NULL;
			p->tp = NULL;
			p->atom = '\0';
			p->tag = -1;
			++str;
		}
		else if (*str == ')')
		{
			flll = 1;
			p = NULL;
			return head;
		}
		else
		{
			++str;
		}
	}
	return head;
}
GLNode* GetHead(GLNode* L)
{
	GLNode* head;
	if (L->tag == 0)
	{
		head = L;
		head->tp = NULL;
		return head;
	}
	else if (L->tag == 1)
	{
		head = L;
		head = L->hp;
		return head;
	}
	else
	{
		printf("error.\n");
	}
}
GLNode* GetTail(GLNode* L)
{
	GLNode* tail;
	tail = L->tp;
	return tail;
}
void output(GLNode* L)
{
	if (L->tp == NULL && L->hp == NULL && L->atom != '0'&&L->tag != -1)
	{
		printf("%c", L->atom);
		flag = 1;
	}
	else
	{
		printf("(");
		GLNode* p = L;
		while (p)
		{
			if (p->tag == 0)
			{
				printf("%c", p->atom);
				flah++;
				p = p->tp;
			}
			else if (p->tag == 1)
			{
				output(p->hp);
				p = p->tp;
			}
			if (p->tag == 0 || p->tag == 1)
			{
				printf(",");
			}
			else
			{
				break;
			}
		}
		flah++;
		printf(")");
	}
}
int main()
{
	char *str;
	char strr[500];
	int choose;
	scanf("%s", strr);
	str = strr;
	GLNode* L = new Node;
	L = CreatList(str);
	printf("generic list: ");
	output(L);
	printf("\n");
	while (1)
	{
		scanf("%d", &choose);
		if (choose == 1)
		{
			printf("destroy tail\n");
			printf("free list node\n");
			L = GetHead(L);
			printf("generic list: ");
			output(L);
			printf("\n");
		}
		else if (choose == 2)
		{
			printf("free head node\n");
			printf("free list node\n");
			L = GetTail(L);
			printf("generic list: ");
			output(L);
			printf("\n");
		}
		else
		{
			printf("error\n");
			break;
		}
		if (flag == 1)
		{
			break;
		}
		if (flah == 1)
		{
			break;
		}
		else
		{
			flah = 0;
		}
	}
}

2.练习

(1)

A = (  )   空表  表长0,深度1

B = ( b, c, d ) 表头b,表尾(c,d),深度1,表长3

C = ( a, B ) = ( a, (b,c,d) )    表头a,表尾(B),深度2,表长2

D = ( A, B, C ) = ( ( ), (b,c,d), (a,(b,c,d)) )表头(),表尾(B,C),表长3,深度3

(2)

D = ( E, F ) =  ( ( a, ( b, c ) ),F )

Head( D ) = E

Tail( D ) = (F)

Head( E ) = a

Tail( E )= ((b,c))

Head( ((b, c)) ) = (b,c)

Tail( ((b, c)) ) = ()

Head( (b, c) ) =b

Tail( (b, c) )=(c)

Head( ( c ) ) =c

Tail( ( c ) ) = ()

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值