三、栈、队列和数组

1.1 栈

//初始化操作
#define maxszie 10
typedef struct{
elemtype data[maxsize];
int top;
}sqstack;

//初始化栈
s.top=-1;
//判栈空
if(s.top==-1)
return true;
//进栈,先判栈满,再进栈
if(S.top==maxsize-1//到达栈顶
return false;
S.top=S.top+1;
S.data[S.top]=x;//S.data[++top]=x;
return true;
//出栈,先判栈是否空
if(s.top==-1)
return false;
x=S.data[S.top];
s.top=s.top-1;//x=S.data[S.top--],top后减
return true;

若栈顶指针一开始指向栈底第一个空元素,S.top=0;
则,后面的入栈和出栈需要相应的,top指针应该后修改,x先操作,当top=maxsize-1||S.data[S.top]!=null时,栈满。

1.2 共享栈

typedef struct{
elemtype data;
int top0;//栈顶
in top1;//栈底
}shstack
//栈满条件:top1+1==top1;

采用共享栈的好处是,节省存储空间,降低发生上溢的可能。
[09真题]
栈s和队列Q的初始状态都为空,元素adcdefg依次进入栈中,若每个元素出栈后立即进入Q中,且已知元素出队顺序为bdcfeag,则栈s的容量至少是?
注意:看清s栈和队列Q,已知出队,因此可知入队序列和s的出栈序列一致。

s栈内出栈
abb
acddc
aeffe
aa
gg

显然,由图表可知s栈的容量至少为3。


2.队列

顺序实现

#define maxsize 10
typedef struct{
elemtype data;
int front;
int rear;
}sqQuene;

2.1循环队列
初始时:Q.front=Q.rear=0;
入队:Q.rear=(Q.rear+1)%maxsize
出队:Q.front=(Q.front+1)%maxsize
队列长度:(Q.rear+maxsize-Q.front)%maxsize;
队满:
1)(Q.rear+1)%maxsize=Q.front;
2)设置tag,入队置1,出队置0;
3设置size,记录队列长度

//循环队列初始化:以下皆以第一种判队满方式为例
Q.front=Q.rear=0;
//判队空
Q.front==Q.rear;
//入队:在队尾入队
if((Q.rear+1)%maxsize==Q.front)
	return false;
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%maxsize;
return true;
//出队:队头
if(Q.front==Q.rear)
return false;
x=Q.data[Q.front];
Q.front=(Q.front+1)%maxsize;
return true;

链式存储:链队
分为带头结点和不带头结点
1)带头结点

typedef struct //结点定义
{
elemtype data;
struct linknode *next;
}Linknode;
typedef struct 
{
linknode *front,*rear;
}linkqueue;//链队队列
//初始化队列
void InitQueue(Linkqueue &Q)
{
Q.front=Q.rear=(linknode *)malloc(sizeof(linknode));
Q.front->next=null;
}
//入队:链队不存在队满,除非内存空间不足
void enQueue(linkqueue &Q,elemtype x)
{
linknode *s=(linknode *)malloc(sizeof(linknode));
s->data=x;
s->next=null;//容易遗漏
Q.rear->next=s;
Q.rear=s;
}
//出队
bool deQueue(linkqueue &Q,elemtype x)
{
if(Q.rear==Q.front)//or Q.front=null;
	return false;//队空
x=Q.front->data;
linknode *p=Q.front->next;//指向出队结点
Q.front->next=p->next;
if(Q.rear==p)
Q.rear=Q.front;
free(p);
return true;
}

2)不带头结点

//入队
void enQueue(linkqueue &Q,elemtype x)
{
//初始化
linknode *s=(linknode *)malloc(sizeof(linknode));
s->data==x;
if(Q.front==null)
	{
	Q.front=Q.rear=s;
	s->next=null;
	}
else{
	s->next=null;//容易遗漏
	Q.rear->next=s;
	Q.rear=s;
	}
}
//出队
bool deQueue(linkqueue &Q,elemtype x)
{
if(Q.rear==Q.front)//or Q.front=null;
	return false;//队空
x=Q.front->data;
linknode *p=Q.front;
Q.font=p->next;//若为最后一个元素,p=Q.rear,Q.rear->next=null 这句执行完以后,Q.front=null
if(Q.rear==p)
	Q.rear=Q.front=null;
return true;
}

2.2双端队列


3.栈和队列的应用

栈:括号匹配中缀表达式求值,函数调用栈(斐波那契数列、求阶乘),
队列:树和图的遍历、cpu的分时处理和多用户任务处理(打印机)
注:并不是所有的递归都要用到栈,还可以使用迭代。递归的主要特点:效率低,但是代码理解简单。


4.数组

普通二维数组的按存储方式可分为行优先和列优先,存储在一个线性表中,为了便于随机存取,也因此需要考虑两个问题,一个是使用多大的空间,另一个是二维数组存到一维线性表里采用怎么样的映射关系。

  • 对于普通二维数组而言,如果采用行优先,目标元素A(i,j)在线性表里的位置应该是:表的起始地址+【(i-1)*二维数组的长度+j列】 * 数组单个元素所占存储空间;
  • 如果采用列优先,相应的有:表的起始地址+【(j-1)*二维数组高度+i】 * 数组单个元素所占存储空间;

4.1 对称矩阵
A[i][j]=A[j][i],由此特点可以得知我们只需要存储A中一半的元素即可,按一半可分为上三角或者下三角,那一共就是(1+n)*n/2个空间大小,那按划分三角的方式和按行和按列,但是由于对称矩阵具有对称的性质,因此,当得知了当i和j互换以后,就可以实现从上三角到下三角的转换,因此,主要讨论行优先和列优先即可(以下都以下三角为例,并且数组从下标0开始,n阶)

  • 下三角+行优先:A[i][j]的位置应该是(j-1)*j/2+i-1;
  • 下三角+列优先:(i-1)(n+n-1+…+n-i+2)/2+j-i=>(i-1)(2n-i+2)/2+(j-i);

4.2 三角阵
三角阵在对称矩阵的基础上需要多一个空间,因此容易知道三角阵的空间大小应该是(1+n)*n/2+1,而假设数组下标从0开始的话,可以将多余的元素刚好存在下标为(1+n)*n/2的位置处,而映射关系应该和对称阵采用列优先的一致
具体来说的话:

  • 上三角+行优先=下三角+列优先;上三角+列优先=下三角+行优先,具体问题具体分析

4.3 三对角矩阵
带状的矩阵;除下标|j-i|<=1外,其他都为0;只有第一行和最后一行只有两个数据元素,其余行元素个数都一致(在假设存入数组下标为1开始的情况下)。

  • 采用行优先,前i-1行应该有3(i-1)-1个元素,那么第i行A[i][j]前面应该有j-i+2个元素why?,所以两者相加就是2i+j-2;

4.4 稀疏矩阵
采用三元组或者十字链表法存储


注意:看题要仔细,注意看下标是规定1还是0开始!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只爱圣女果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值