栈、队列和数组(包括求解迷宫问题)

news/2024/10/25 17:26:28/

 1.1 琐碎知识点

栈、队列、数组是线性存储结构,它们都是一段连续的内存空间,其中栈和队列是动态的,而数组是静态的。它们的区别在于:

  • 栈:后进先出,只能在栈顶进行插入和删除操作。
  • 队列:先进先出,只能在队尾进行插入操作,在队头进行删除操作。
  • 数组:可以随机访问,但插入和删除操作比较麻烦。

n个不同元素进栈,出栈元素的排列个数可为\frac{1}{n+1}C_{n}^{2n}\textrm{} 

判断输出序列的合法性:按栈的序列可以的,双端队列也可以

栈和队列的应用:

栈:①括号匹配 ②表达式求值 ③递归

队列:①层次遍历 ②计算机系统

1.2  栈在表达式求值中的应用

规则:①运算项直接进栈 ②运算符级别高的直接进,低的就将栈内容清至级别低的地方为止

将中缀表达式转换为后缀表达式的具体过程如下:

  1. 初始化两个栈:运算符栈s1和储存中间结果的栈s2;
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数时,将其压s2;
  4. 遇到运算符时,比较其与s1栈顶运算符的优先级:
    1. 如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
    2. 否则,若优先级比栈顶运算符的较高或相等,也将运算符压入s1;
    3. 否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4--1)与s1中新的栈顶运算符相比较;
  5. 遇到括号时:
    1. 如果是左括号“(”,则直接压入s1;
    2. 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
  6. 重复步骤2至5,直到表达式的最右边;
  7. 将s1中剩余的运算符依次弹出并压入s2;
  8. 依次弹出s2中的元素并输出,结果的逆序即为该中缀表达式对应的后缀表达式。

例如:A+B*(C-D)-E/F转换为后缀表达式为:ABCD-*+EF/-

顺序栈基本运算算法:

//顺序栈基本运算算法
#include <stdio.h>
#include <malloc.h>
#define MaxSize 100
typedef char ElemType;
typedef struct 
{	ElemType data[MaxSize];int top;				//栈指针
} SqStack;					//顺序栈类型void InitStack(SqStack *&s)
{s=(SqStack *)malloc(sizeof(SqStack));s->top=-1;
} void DestroyStack(SqStack *&s)
{free(s);
}bool StackEmpty(SqStack *s)
{return(s->top==-1);
}bool Push(SqStack *&s,ElemType e)
{if (s->top==MaxSize-1)    //栈满的情况,即栈上溢出return false;s->top++;s->data[s->top]=e;return true;
}bool Pop(SqStack *&s,ElemType &e)
{if (s->top==-1)		//栈为空的情况,即栈下溢出return false;e=s->data[s->top];s->top--;return true;
} bool GetTop(SqStack *s,ElemType &e)
{if (s->top==-1) 		//栈为空的情况,即栈下溢出return false;e=s->data[s->top];return true;
}

求简单表达式的值 ----中缀表达式转换为后缀表达式的具体过程实现

//求简单表达式的值
#include <stdio.h>
#include <stdlib.h>
#define MaxSize 100
//---------------------------------------------------------
//--运算符栈基本运算---------------------------------------
//---------------------------------------------------------
typedef struct 
{	char data[MaxSize];			//存放运算符int top;					//栈顶指针
} SqStack;
void InitStack(SqStack *&s)		//初始化栈
{	s=(SqStack *)malloc(sizeof(SqStack));s->top=-1;
}
void DestroyStack(SqStack *&s)	//销毁栈
{free(s);
}
bool StackEmpty(SqStack *s)		//判断栈是否为空
{return(s->top==-1);
}
bool Push(SqStack *&s,char e)	//进栈元素e
{	if (s->top==MaxSize-1)return false;s->top++;s->data[s->top]=e;return true;
}
bool Pop(SqStack *&s,char &e)	//出栈元素e
{	if (s->top==-1)	return false;e=s->data[s->top];s->top--;return true;
}
bool GetTop(SqStack *s,char &e)	//取栈顶元素e
{	if (s->top==-1)	return false;e=s->data[s->top];return true;
}
//---------------------------------------------------------void trans(char *exp,char postexp[])	//将算术表达式exp转换成后缀表达式postexp
{char e;SqStack *Optr;						//定义运算符栈InitStack(Optr);					//初始化运算符栈int i=0;							//i作为postexp的下标while (*exp!='\0')					//exp表达式未扫描完时循环{	switch(*exp){case '(':						//判定为左括号Push(Optr,'(');				//左括号进栈exp++;						//继续扫描其他字符break;case ')':						//判定为右括号Pop(Optr,e);				//出栈元素ewhile (e!='(')				//不为'('时循环{postexp[i++]=e;			//将e存放到postexp中Pop(Optr,e);			//继续出栈元素e}exp++;						//继续扫描其他字符break;case '+':						//判定为加或减号case '-':while (!StackEmpty(Optr))	//栈不空循环{GetTop(Optr,e);			//取栈顶元素eif (e!='(')				//e不是'('{postexp[i++]=e;		//将e存放到postexp中Pop(Optr,e);		//出栈元素e}else					//e是'(时退出循环break;}Push(Optr,*exp);			//将'+'或'-'进栈exp++;						//继续扫描其他字符break;case '*':						//判定为'*'或'/'号case '/':while (!StackEmpty(Optr))	//栈不空循环{GetTop(Optr,e);			//取栈顶元素eif (e=='*' || e=='/')	//将栈顶'*'或'/'运算符出栈并存放到postexp中{postexp[i++]=e;		//将e存放到postexp中Pop(Optr,e);		//出栈元素e}else					//e为非'*'或'/'运算符时退出循环break;}Push(Optr,*exp);			//将'*'或'/'进栈exp++;						//继续扫描其他字符break;default:				//处理数字字符while (*exp>='0' && *exp<='9') //判定为数字{	postexp[i++]=*exp;exp++;}postexp[i++]='#';	//用#标识一个数值串结束}}while (!StackEmpty(Optr))	//此时exp扫描完毕,栈不空时循环{Pop(Optr,e);			//出栈元素epostexp[i++]=e;			//将e存放到postexp中}postexp[i]='\0';			//给postexp表达式添加结束标识DestroyStack(Optr);			//销毁栈		
}
//---------------------------------------------------------
//--操作数栈基本运算---------------------------------------
//---------------------------------------------------------
typedef struct 
{	double data[MaxSize];			//存放数值int top;						//栈顶指针
} SqStack1;
void InitStack1(SqStack1 *&s)		//初始化栈
{	s=(SqStack1 *)malloc(sizeof(SqStack1));s->top=-1;
}
void DestroyStack1(SqStack1 *&s)	//销毁栈
{free(s);
}
bool StackEmpty1(SqStack1 *s)		//判断栈是否为空
{return(s->top==-1);
}
bool Push1(SqStack1 *&s,double e)	//进栈元素e
{	if (s->top==MaxSize-1)return false;s->top++;s->data[s->top]=e;return true;
}
bool Pop1(SqStack1 *&s,double &e)	//出栈元素e
{	if (s->top==-1)	return false;e=s->data[s->top];s->top--;return true;
}
bool GetTop1(SqStack1 *s,double &e)	//取栈顶元素e
{	if (s->top==-1)	return false;e=s->data[s->top];return true;
}
//---------------------------------------------------------double compvalue(char *postexp)	//计算后缀表达式的值
{double d,a,b,c,e;SqStack1 *Opnd;				//定义操作数栈InitStack1(Opnd);			//初始化操作数栈while (*postexp!='\0')		//postexp字符串未扫描完时循环{	switch (*postexp){case '+':				//判定为'+'号Pop1(Opnd,a);		//出栈元素aPop1(Opnd,b);		//出栈元素bc=b+a;				//计算cPush1(Opnd,c);		//将计算结果c进栈break;case '-':				//判定为'-'号Pop1(Opnd,a);		//出栈元素aPop1(Opnd,b);		//出栈元素bc=b-a;				//计算cPush1(Opnd,c);		//将计算结果c进栈break;case '*':				//判定为'*'号Pop1(Opnd,a);		//出栈元素aPop1(Opnd,b);		//出栈元素bc=b*a;				//计算cPush1(Opnd,c);		//将计算结果c进栈break;case '/':				//判定为'/'号Pop1(Opnd,a);		//出栈元素aPop1(Opnd,b);		//出栈元素bif (a!=0){c=b/a;			//计算cPush1(Opnd,c);	//将计算结果c进栈break;}else{	printf("\n\t除零错误!\n");exit(0);		//异常退出}break;default:				//处理数字字符d=0;				//将连续的数字字符转换成对应的数值存放到d中while (*postexp>='0' && *postexp<='9')   //判定为数字字符{	d=10*d+*postexp-'0';  postexp++;}Push1(Opnd,d);		//将数值d进栈break;}postexp++;				//继续处理其他字符}GetTop1(Opnd,e);			//取栈顶元素eDestroyStack1(Opnd);		//销毁栈		return e;					//返回e
}
int main()
{char exp[]="(56-20)/(4+2)";char postexp[MaxSize];trans(exp,postexp);printf("中缀表达式:%s\n",exp);printf("后缀表达式:%s\n",postexp);printf("表达式的值:%g\n",compvalue(postexp));return 1;
}

用栈求解迷宫问题 

//用栈求解迷宫问题
#include <stdio.h>
#include <malloc.h>
#define MaxSize 100
#define M 8
#define N 8
int mg[M+2][N+2]=
{	{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,0,0,1,1,0,0,1},{1,0,1,1,1,0,0,0,0,1},{1,0,0,0,1,0,0,0,0,1},{1,0,1,0,0,0,1,0,0,1},{1,0,1,1,1,0,1,1,0,1},{1,1,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1}
};
//---------------------------------------------------------
//--迷宫栈基本运算---------------------------------------
//---------------------------------------------------------
typedef struct
{int i;				//当前方块的行号int j;				//当前方块的列号int di;				//di是下一可走相邻方位的方位号
} Box;
typedef struct
{Box data[MaxSize];	//存放方块int top;			//栈顶指针
} StType;				//定义栈类型void InitStack(StType *&s)		//初始化栈
{	s=(StType *)malloc(sizeof(StType));s->top=-1;
}
void DestroyStack(StType *&s)	//销毁栈
{free(s);
}
bool StackEmpty(StType *s)		//判断栈是否为空
{return(s->top==-1);
}
bool Push(StType *&s,Box e)	//进栈元素e
{if (s->top==MaxSize-1)return false;s->top++;s->data[s->top]=e;return true;
}
bool Pop(StType *&s,Box &e)	//出栈元素e
{if (s->top==-1)	return false;e=s->data[s->top];s->top--;return true;
}
bool GetTop(StType *s,Box &e)	//取栈顶元素e
{if (s->top==-1)	return false;e=s->data[s->top];return true;
}
//---------------------------------------------------------
bool mgpath(int xi,int yi,int xe,int ye)	//求解路径为:(xi,yi)->(xe,ye)
{Box path[MaxSize], e;int i,j,di,i1,j1,k;bool find;StType *st;								//定义栈stInitStack(st);							//初始化栈顶指针e.i=xi; e.j=yi;	e.di=-1;				//设置e为入口Push(st,e);								//方块e进栈mg[xi][yi]=-1;							//入口的迷宫值置为-1避免重复走到该方块while (!StackEmpty(st))					//栈不空时循环{GetTop(st,e);						//取栈顶方块ei=e.i; j=e.j; di=e.di;if (i==xe && j==ye)					//找到了出口,输出该路径{ printf("一条迷宫路径如下:\n");k=0;while (!StackEmpty(st)){Pop(st,e);					//出栈方块epath[k++]=e;				//将e添加到path数组中}while (k>=1){k--;printf("\t(%d,%d)",path[k].i,path[k].j);if ((k+2)%5==0)				//每输出每5个方块后换一行printf("\n");  }printf("\n");DestroyStack(st);				//销毁栈return true;					//输出一条迷宫路径后返回true}find=false;while (di<4 && !find)				//找相邻可走方块(i1,j1){	di++;switch(di){case 0:i1=i-1; j1=j;   break;case 1:i1=i;   j1=j+1; break;case 2:i1=i+1; j1=j;   break;case 3:i1=i;   j1=j-1; break;}if (mg[i1][j1]==0) find=true;	//找到一个相邻可走方块,设置find我真}if (find)							//找到了一个相邻可走方块(i1,j1){	st->data[st->top].di=di;		//修改原栈顶元素的di值e.i=i1; e.j=j1; e.di=-1;Push(st,e);						//相邻可走方块e进栈mg[i1][j1]=-1;					//(i1,j1)的迷宫值置为-1避免重复走到该方块}else								//没有路径可走,则退栈{	Pop(st,e);						//将栈顶方块退栈mg[e.i][e.j]=0;					//让退栈方块的位置变为其他路径可走方块}}DestroyStack(st);						//销毁栈return false;							//表示没有可走路径,返回false
}
int main()
{mgpath(1,1,M,N);return 1;
}

1.3 环形队列

顺序队列(环形队列)基本运算算法

//顺序队列(环形队列)基本运算算法
#include <stdio.h>
#include <malloc.h>
#define MaxSize 100
typedef char ElemType;
typedef struct 
{	ElemType data[MaxSize];int front,rear;		//队首和队尾指针
} SqQueue;
void InitQueue(SqQueue *&q)
{	q=(SqQueue *)malloc (sizeof(SqQueue));q->front=q->rear=0;
}
void DestroyQueue(SqQueue *&q)
{free(q);
}
bool QueueEmpty(SqQueue *q)
{return(q->front==q->rear);
}
bool enQueue(SqQueue *&q,ElemType e)
{	if ((q->rear+1)%MaxSize==q->front)	//队满上溢出return false;q->rear=(q->rear+1)%MaxSize;q->data[q->rear]=e;return true;
}
bool deQueue(SqQueue *&q,ElemType &e)
{	if (q->front==q->rear)		//队空下溢出return false;q->front=(q->front+1)%MaxSize;e=q->data[q->front];return true;
}

用队列求解迷宫问题 

//用队列求解迷宫问题
#include <stdio.h>
#include <malloc.h>
#define MaxSize 100
#define M 8
#define N 8
int mg[M+2][N+2]=
{	{1,1,1,1,1,1,1,1,1,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,1,0,0,0,1,0,1},{1,0,0,0,0,1,1,0,0,1},{1,0,1,1,1,0,0,0,0,1},{1,0,0,0,1,0,0,0,0,1},{1,0,1,0,0,0,1,0,0,1},{1,0,1,1,1,0,1,1,0,1},{1,1,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1}
};
//----------------------------------------------------------
//-非环形队列的基本运算算法---------------------------------
//----------------------------------------------------------
typedef struct 
{	int i,j;						//方块的位置int pre;						//本路径中上一方块在队列中的下标
} Box;								//方块类型
typedef struct
{Box data[MaxSize];int front,rear;					//队头指针和队尾指针
} QuType;							//顺序队类型void InitQueue(QuType *&q)			//初始化队列
{	q=(QuType *)malloc (sizeof(QuType));q->front=q->rear=-1;
}
void DestroyQueue(QuType *&q)		//销毁队列
{free(q);
}
bool QueueEmpty(QuType *q)			//判断队列是否为空
{return(q->front==q->rear);
}
bool enQueue(QuType *&q,Box e)		//进队列
{	if (q->rear==MaxSize-1)			//队满上溢出return false;				//返回假q->rear++;						//队尾增1q->data[q->rear]=e;				//rear位置插入元素ereturn true;					//返回真
}
bool deQueue(QuType *&q,Box &e)	//出队列
{	if (q->front==q->rear)			//队空下溢出return false;q->front++;e=q->data[q->front];return true;
}
//----------------------------------------------------------void print(QuType *qu,int front)	//从队列qu中输出路径
{int k=front,j,ns=0;printf("\n");do				//反向找到最短路径,将该路径上的方块的pre成员设置成-1{	j=k;k=qu->data[k].pre;qu->data[j].pre=-1;} while (k!=0);printf("一条迷宫路径如下:\n");k=0;while (k<MaxSize)  //正向搜索到pre为-1的方块,即构成正向的路径{	if (qu->data[k].pre==-1){	ns++;printf("\t(%d,%d)",qu->data[k].i,qu->data[k].j);if (ns%5==0) printf("\n");	//每输出每5个方块后换一行}k++;}printf("\n");
}
bool mgpath1(int xi,int yi,int xe,int ye)	//搜索路径为:(xi,yi)->(xe,ye)
{Box e;int i,j,di,i1,j1;QuType *qu;						//定义顺序队指针quInitQueue(qu);					//初始化队列que.i=xi; e.j=yi; e.pre=-1;enQueue(qu,e);					//(xi,yi)进队mg[xi][yi]=-1;					//将其赋值-1,以避免回过来重复搜索while (!QueueEmpty(qu))			//队不空且循环{	deQueue(qu,e);				//出队方块e,由于不是环形队列,该出队元素仍在队列中i=e.i; j=e.j;if (i==xe && j==ye)			//找到了出口,输出路径{	print(qu,qu->front);	//调用print函数输出路径DestroyQueue(qu);		//销毁队列return true;			//找到一条路径时返回真}for (di=0;di<4;di++)		//循环扫描每个方位,把每个可走的方块插入队列中{	switch(di){case 0:i1=i-1; j1=j;   break;case 1:i1=i;   j1=j+1; break;case 2:i1=i+1; j1=j;   break;case 3:i1=i;   j1=j-1; break;}if (mg[i1][j1]==0){e.i=i1; e.j=j1; e.pre=qu->front;	//指向路径中上一个方块的下标enQueue(qu,e);		//(i1,j1)方块进队mg[i1][j1]=-1;		//将其赋值-1,以避免回过来重复搜索}}}DestroyQueue(qu);			//销毁队列return false;				//未找到任何路径时返回假
}
int main()
{mgpath1(1,1,M,N);return 1;
}

1.4 数组和特殊矩阵

1.4.1 数组的存储结构

列优先:存储单元先行后列

列优先:存储单元先列后行

1.4.2 特殊矩阵的压缩存储

压缩存储:多个值相同的元素只分配一个存储空间,对零元素不分配存储空间

对称矩阵:

 三角矩阵:

1.4.3 稀疏矩阵 

 稀疏矩阵:

//稀疏矩阵的三元组表示-算法
#include <stdio.h>
#define M 6
#define N 7
#define MaxSize  100         //矩阵中非零元素最多个数
typedef int ElemType;
typedef struct
{int r;					//行号int c;					//列号ElemType d;				//元素值
} TupNode;					//三元组定义
typedef struct 
{	int rows;				//行数int cols;				//列数int nums;				//非零元素个数TupNode data[MaxSize];
} TSMatrix;					//三元组顺序表void CreatMat(TSMatrix &t,ElemType A[M][N])  //从一个二维稀疏矩阵创建其三元组表示
{int i,j;t.rows=M;t.cols=N;t.nums=0;for (i=0;i<M;i++){for (j=0;j<N;j++) if (A[i][j]!=0) 	//只存储非零元素{t.data[t.nums].r=i;t.data[t.nums].c=j;t.data[t.nums].d=A[i][j];t.nums++;}}
}
bool Value(TSMatrix &t,ElemType x,int i,int j)  //三元组元素赋值
{int k=0,k1;if (i>=t.rows || j>=t.cols)return false;				//失败时返回falsewhile (k<t.nums && i>t.data[k].r) k++;					//查找行while (k<t.nums && i==t.data[k].r && j>t.data[k].c) k++;//查找列if (t.data[k].r==i && t.data[k].c==j)	//存在这样的元素t.data[k].d=x;else									//不存在这样的元素时插入一个元素{	for (k1=t.nums-1;k1>=k;k1--){t.data[k1+1].r=t.data[k1].r;t.data[k1+1].c=t.data[k1].c;t.data[k1+1].d=t.data[k1].d;}t.data[k].r=i;t.data[k].c=j;t.data[k].d=x;t.nums++;}return true;						//成功时返回true
}bool Assign(TSMatrix t,ElemType &x,int i,int j)  //将指定位置的元素值赋给变量
{int k=0;if (i>=t.rows || j>=t.cols)return false;			//失败时返回falsewhile (k<t.nums && i>t.data[k].r) k++;					//查找行while (k<t.nums && i==t.data[k].r && j>t.data[k].c) k++;//查找列if (t.data[k].r==i && t.data[k].c==j)x=t.data[k].d;elsex=0;				//在三元组中没有找到表示是零元素return true;			//成功时返回true
}
void DispMat(TSMatrix t)		//输出三元组
{int i;if (t.nums<=0)			//没有非零元素时返回return;printf("\t%d\t%d\t%d\n",t.rows,t.cols,t.nums);printf("\t------------------\n");for (i=0;i<t.nums;i++)printf("\t%d\t%d\t%d\n",t.data[i].r,t.data[i].c,t.data[i].d);
}
void TranTat(TSMatrix t,TSMatrix &tb)		//矩阵转置
{int p,q=0,v;					//q为tb.data的下标tb.rows=t.cols;tb.cols=t.rows;tb.nums=t.nums;if (t.nums!=0)					//当存在非零元素时执行转置{for (v=0;v<t.cols;v++)		//tb.data[q]中的记录以c域的次序排列for (p=0;p<t.nums;p++)	//p为t.data的下标if (t.data[p].c==v){tb.data[q].r=t.data[p].c;tb.data[q].c=t.data[p].r;tb.data[q].d=t.data[p].d;q++;}}
}
int main()
{TSMatrix t,tb;int x,y=10;int A[6][7]={{0,0,1,0,0,0,0},{0,2,0,0,0,0,0},{3,0,0,0,0,0,0},{0,0,0,5,0,0,0},{0,0,0,0,6,0,0},{0,0,0,0,0,7,4}};CreatMat(t,A);printf("b:\n"); DispMat(t);if (Assign(t,x,2,5)==true)  //调用时返回trueprintf("Assign(t,x,2,5)=>x=%d\n",x);else  //调用时返回falseprintf("Assign(t,x,2,5)=>参数错误\n");Value(t,y,2,5);printf("执行Value(t,10,2,5)\n");if (Assign(t,x,2,5)==true)  //调用时返回trueprintf("Assign(t,x,2,5)=>x=%d\n",x);else  //调用时返回falseprintf("Assign(t,x,2,5)=>参数错误\n");printf("b:\n"); DispMat(t);TranTat(t,tb);printf("tb:\n"); DispMat(tb);return 1;
}

 

//稀疏矩阵的十字链表表示
#include <stdio.h>
#include <malloc.h>
#define M 3         			//矩阵行
#define N 4           			//矩阵列
#define Max ((M)>(N)?(M):(N))   //矩阵行列较大者
typedef int ElemType;
typedef struct mtxn 
{ int row;					//行号int col;					//列号struct mtxn *right,*down;	//向右和向下的指针union {ElemType value;struct mtxn *link;} tag;
} MatNode;			//十字链表类型
void CreatMat(MatNode *&mh,ElemType a[][N])	//创建a的十字链表
{int i,j;MatNode *h[Max],*p,*q,*r;mh=(MatNode *)malloc(sizeof(MatNode));//创建十字链表的头结点mh->row=M;mh->col=N;r=mh;					//r指向尾结点for (i=0;i<Max;i++)		//采用尾插法创建头结点h1,h2,…循环链表{h[i]=(MatNode *)malloc(sizeof(MatNode));h[i]->down=h[i]->right=h[i];		//将down和right方向置为循环的r->tag.link=h[i];					//将h[i]加到链表中r=h[i];}r->tag.link=mh;							//置为循环链表for (i=0;i<M;i++)						//处理每一行{for (j=0;j<N;j++)					//处理每一列{if (a[i][j]!=0)					//处理非零元素{p=(MatNode *)malloc(sizeof(MatNode));	//创建一个新结点p->row=i;p->col=j;p->tag.value=a[i][j];q=h[i];      					//查找在行表中的插入位置while (q->right!=h[i] && q->right->col<j) q=q->right;p->right=q->right;q->right=p;	//完成行表的插入q=h[j];      					//查找在列表中的插入位置while (q->down!=h[j] && q->down->row<i) q=q->down;p->down=q->down;q->down=p;  	//完成列表的插入}}}
}
void DestroyMat(MatNode *&mh)		//销毁十字链表
{MatNode *pre,*p,*mp;mp=mh->tag.link;				//mp指向h[i]while (mp!=mh)					//释放所有数据结点{pre=mp->right;				//pre指向h[i]的行首结点if (pre!=mp)				//h[i]不空{p=pre->right;			//p指向结点pre的后继结点while (p!=mp){free(pre);pre=p; p=p->right;}}mp=mp->tag.link;			//mp指向下一个头结点}//释放所有的头结点pre=mh->tag.link;				//pre指向h[i]p=pre->tag.link;				//p指向h[i+1]while (p!=mh){free(pre);pre=p; p=p->tag.link;}free(mh);
}
void DispMat(MatNode *mh)		//输出十字链表
{MatNode *p,*q;printf("行=%d  列=%d\n", mh->row,mh->col);p=mh->tag.link;while (p!=mh) {	q=p->right;while (p!=q) 		//输出一行非零元素{printf("%d\t%d\t%d\n", q->row,q->col,q->tag.value);q=q->right;}p=p->tag.link;}
}
//本主程序用于调试
int main()
{ElemType a[M][N]={{1,0,0,2},{0,0,3,0},{0,0,0,4}};MatNode *mx;CreatMat(mx,a);printf("a的十字链表:\n");DispMat(mx);DestroyMat(mx);return 1;
}

 

1.4.4 三对角矩阵 

1.4.5 广义表 

什么是广义表

广义表,又称列表,也是一种线性存储结构。

同数组类似,广义表中既可以存储不可再分的元素,也可以存储广义表,记作:

LS = (a1,a2,…,an)

其中,LS 代表广义表的名称,an 表示广义表存储的数据。广义表中每个 ai 既可以代表单个元素,也可以代表另一个广义表。

原子和子表

通常,广义表中存储的单个元素称为 "原子",而存储的广义表称为 "子表"。

例如创建一个广义表 LS = {1,{1,2,3}},我们可以这样解释此广义表的构成:广义表 LS 存储了一个原子 1 和子表 {1,2,3}。

以下是广义表存储数据的一些常用形式:
  • A = ():A 表示一个广义表,只不过表是空的。
  • B = (e):广义表 B 中只有一个原子 e。
  • C = (a,(b,c,d)) :广义表 C 中有两个元素,原子 a 和子表 (b,c,d)。
  • D = (A,B,C):广义表 D 中存有 3 个子表,分别是A、B和C。这种表示方式等同于 D = ((),(e),(b,c,d)) 。
  • E = (a,E):广义表 E 中有两个元素,原子 a 和它本身。这是一个递归广义表,等同于:E = (a,(a,(a,…)))。

注意,A = () 和 A = (()) 是不一样的。前者是空表,而后者是包含一个子表的广义表,只不过这个子表是空表。

广义表的表头和表尾

当广义表不是空表时,称第一个数据(原子或子表)为"表头",剩下的数据构成的新广义表为"表尾"。

强调一下,除非广义表为空表,否则广义表一定具有表头和表尾,且广义表的表尾一定是一个广义表。

例如在广义表中 LS={1,{1,2,3},5} 中,表头为原子 1,表尾为子表 {1,2,3} 和原子 5 构成的广义表,即 {{1,2,3},5}。

再比如,在广义表 LS = {1} 中,表头为原子 1 ,但由于广义表中无表尾元素,因此该表的表尾是一个空表,用 {} 表示。

//广义表基本运算算法
#include <stdio.h>
#include <malloc.h>
#include "glnode.h"
int GLLength(GLNode *g)			//求广义表g的长度
{int n=0;GLNode *g1;g1=g->val.sublist;			//g指向广义表的第一个元素while (g1!=NULL){	n++;					//累加元素个数g1=g1->link;}return n;
}
int GLDepth(GLNode *g)			//求广义表g的深度
{GLNode *g1;int maxd=0,dep;if (g->tag==0)				//为原子时返回0return 0;g1=g->val.sublist;			//g1指向第一个元素if (g1==NULL)				//为空表时返回1return 1;while (g1!=NULL)			//遍历表中的每一个元素{	if (g1->tag==1)			//元素为子表的情况{dep=GLDepth(g1);	//递归调用求出子表的深度if (dep>maxd)		//maxd为同一层所求过的子表中深度的最大值maxd=dep;}g1=g1->link;			//使g1指向下一个元素}return(maxd+1);				//返回表的深度
}
GLNode *CreateGL(char *&s)				//创建由括号表示法表示s的广义表链式存储结构
{GLNode *g;char ch=*s++;						//取一个字符if (ch!='\0')						//串未结束判断{g=(GLNode *)malloc(sizeof(GLNode));//创建一个新结点if (ch=='(')					//当前字符为左括号时{g->tag=1;					//新结点作为表头结点g->val.sublist=CreateGL(s); //递归构造子表并链到表头结点}else if (ch==')') g=NULL;           			//遇到')'字符,g置为空else if (ch=='#')				//遇到'#'字符,表示为空表g=NULL;else							//为原子字符{g->tag=0;					//新结点作为原子结点g->val.data=ch;}}else								//串结束,g置为空g=NULL;ch=*s++;                           	//取下一个字符if (g!=NULL)                      	//串未结束,继续构造兄递结点if (ch==',')                  	//当前字符为','g->link=CreateGL(s);   		//递归构造兄递结点else                            //没有兄弟了,将兄弟指针置为NULLg->link=NULL;return g;                     		//返回广义表g
}
void DestroyGL(GLNode *&g)		//销毁广义表
{GLNode *g1,*g2;g1=g->val.sublist;			//g1指向广义表的第一个元素while (g1!=NULL)			//遍历所有元素{if (g1->tag==0)			//若为原子结点{	g2=g1->link;		//g2临时保存兄弟结点free(g1);			//释放g1所指原子结点g1=g2;				//g1指向后继兄弟结点}else					//若为子表{	g2=g1->link;		//g2临时保存兄弟结点DestroyGL(g1);		//递归释放g1所指子表的空间g1=g2;				//g1指向后继兄弟结点}}free(g);					//释放头结点空间
}void DispGL(GLNode *g)					//输出广义表g
{if (g!=NULL)                 		//表不为空判断{									//先处理g的元素if (g->tag==0)               	//g的元素为原子时printf("%c", g->val.data);  //输出原子值else							//g的元素为子表时{printf("(");                //输出'('if (g->val.sublist==NULL)  	//为空表时printf("#");else						//为非空子表时DispGL(g->val.sublist); //递归输出子表printf(")");               	//输出')'}if (g->link!=NULL) {printf(",");DispGL(g->link);            //递归输出后续表的内容}}
}


http://www.ppmy.cn/news/315256.html

相关文章

西农大 C plus

问题 K: oop实习-11.运算符重载 题目描述 定义有理数类&#xff08;分母不为0的分数&#xff0c;分子分母均为整数&#xff09;Rational&#xff0c;实现相应操作符的重载。 &#xff08;1&#xff09;定义私有数据成员&#xff1a;分子int iUp; 分母 int iDown。 &#xff08…

程序员面试题精选100题(51)-顺时针打印矩阵

// 程序员面试题精选100题(51)-顺时针打印矩阵.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h" #include <iostream> using namespace std; #define M 9 #define N 4 int _tmain(int argc, _TCHAR* argv[]) {int arr[M][N];int all0;int i,j,iup0,…

运算符重载例题

用的是vs2019编译器 这是一个有关运算符重载的例题&#xff0c;希望大家作以参考 定义有理数类&#xff08;分母不为0的分数&#xff0c;分子分母均为整数&#xff09;Rational&#xff0c;实现相应操作符的重载。 &#xff08;1&#xff09;定义私有数据成员&#xff1a;分子…

FPGA实现深度学习系列之卷积神经网络算法描述

这里全部内容都是由这个网址转载过来的。 https://tech.youmi.net/2016/07/163347168.html 解说&#xff1a; 关于算法的完成。需要看很多的文章和视频才能有更好的理解和领悟。这里就随便点一下。 1&#xff0c;FPGA作为部署终端&#xff0c;只执行前向传导任务。并不执行…

十字链表c语言实验报告,矩阵加法(基于十字链表)及C语言代码实现

矩阵之间能够进行加法运算的前提条件是:各矩阵的行数和列数必须相等。 在行数和列数都相等的情况下,矩阵相加的结果就是矩阵中对应位置的值相加所组成的矩阵,例如: 采用链式存储结构存储稀疏矩阵三元组的方法,称为“十字。 十字链表法表示矩阵 例如,用十字链表法表示矩阵…

万字博文讲解如何用shell来实现一个俄罗斯方块小游戏

文章目录 1.游戏效果运行图&#xff1a;2. 前置知识与游戏进程设计&#xff1a;2.1: 有关 $0,$1,$2,...$9, 和 $!2.2 进程设计 3.进程间信号传递3.1 RunAsKeyReceiver接收到用户的键盘输入后是如何把信号传递给RunAsDisplayer 进程的 4. 使用echo进行字符打印4.1 打印带颜色背景…

计算机开发日语词汇笔记二

プルダウンリスト&#xff1a;下拉列表&#xff0c;“pull-down list”。 取得できない場合、○○のプルダウンリストに値は設定されない。 不给○○下拉列表赋值。 プルダウンリストに全ての項目を表示する。 下拉列表中显示所有的列表。 エビデンス&#xff1a;成果&…

飞腾(ARM V8)平台实现FFT

最近在做飞腾上的FFT优化&#xff0c;记录一下以后用。 目前实现了基2FFT&#xff0c;使用arm提供的neon接口做了并行计算。算法原理网上很多&#xff0c;这里就不讲了&#xff0c;记录复数正向优化方法。 优化思路&#xff1a; 第一层蝶形计算&#xff1a; 第一层的蝶形因子都…