栈
定义
栈是限定只在表尾进行插入和删除操作的线性表;
允许进行插入和删除的一端称为栈顶,另一端称为栈底;
栈又称为先进后出的线性表。
顺序储存结构
结构
//顺序储存结构
typedef int seletype;//假设数据域为int型
typedef struct
{
selemtype data[maxsize];
int top;//栈顶
}sqstack;
进栈
#define error -1
#define ok 1
status push(sqstack *s,selemtype e)//将数据e进栈s
{
if(s->top==maxsize-1)//当栈满时,返回error=-1;
return error;
s->top++;//栈顶加一
s->data[s->top]=e;
return ok;//ok=1;
}
出栈
//出栈操作
status pop(sqstack *s,selemtype *e)//删除栈顶元素,并将栈顶返回给e
{
if(s->top==-1)//当栈为空时,删除失败
return error;
*e=s->data[s->top];//将要删除的栈顶元素返回给e
s->top--;//栈顶-1
return ok;
}
两栈共享空间
两个栈顶的设置:将两个栈的栈顶设置在数组的两端,向中间靠拢。
注意:使用这样的数据结构,通常都是当两个栈的空间需求有相反关系的时候,例如买股票有人赔就有人赚。这样使用两栈共享才比较有意义。否则两个栈都在不停的增长,很快栈就会溢出。
代码:
//两栈共享空间结构
typedef struct {
selemtype data[maxsize];
int top1; //栈1的顶指针
int top2; //栈2的顶指针
}sqdoublestack;
//入栈操作
status push(sqdoublestack *s,selemtype e,int stacknumber)//将数据e插入到s中,stacknumber表示要插入到哪个栈中1或2
{
if(s->top1+1==s->top2)//当top1的下一个为top2时,这个栈满了,无法push
return error;
if(stacknumber==1)//放到栈1中去
{
s->data[s->top1]=e;
top1++;//top1后移一位
}
else if(stacknumber==2)//放到栈2中区
{
s->data[s->top2] =e;
top2--;//top2前移一位
}
return ok;
}
//出栈操作
status pop(sqdoublestack *s,selemtype *e,int stacknumber)//将共享栈s中的栈stacknumber的栈顶删除并且返回给e
{
if(stacknumber==1)//删除栈1的栈顶
{
if(s->top1==-1)//栈1为空,返回删除错误
return error;
*e=s->data[s->top1] ;
top1--;//栈1的栈顶前移
}
else if(stacknumber==2)//删除栈2的栈顶
{
if(s->top2==maxsize-1)
return error;
*e=s->data[s->top2];
top++;//栈2的栈顶后移
}
}
链式储存结构
栈的链式储存结构,称为链栈;
因为链表的头结点更加方便删除和插入,所以将第一个结点计为栈顶,只需要对top->next进行操作即可。
结构
//栈的链式储存结构
//每个结点的结构体定义
typedef struct stacknode
{
selemtype data;
struct stacknode *next;
}stacknode,*linkstackptr;//stacknode为每个结点的结构体,*linkstackptr结构体指针
//链栈
typedef struct linkstack
{
linkstackptr top;//指向栈顶的指针
int count;//表示栈中元素的个数
};
进栈
因为是链式储存,不需要担心溢出问题,随时用随时申请,方便很多。
//入栈
status push(linkstack *s,selemtype e)//将e入栈
{
//先申请一个stacknode的空间,将e放入
linkstackptr t=(linkstacknode)malloc(sizeof(stacknode));
t->data=e;
//插入到top->的后面即可
t->next=s->top;
s->top=t;
s->count++;
return ok;
}
出栈
//出栈
status pop(linkstack *s,selemtype *e)//删除栈顶元素并放入e中
{
linkstackptr p;
if(s->top==NULL)//若为空栈
return error;
*e=s->top->data;
p-s->top;
s->top=s->top->next;
free(p);
s->count--;//链栈长度-1
return ok;
}
递归
斐波那契数列迭代实现
代码:
int main()
{
int i;
int a[40];
a[0]=0;
a[1]=1;
printf("a[0]=0\na[1]=1\n");
for(i=2;i<40;i++)
printf("a[%d]=%d\n",i,a[i-1]+a[i-2]);//当前项等于前两项的和
return 0;
}
斐波那契数列栈实现
代码:
int fbi(int i)
{
//函数调用结束的条件
if(i==0) return 0;
else if(i==1) return 1;
else return fbi(i-1)+fbi(i-2);
}
int main()
{
int i;
for(i=0;i<40;i++)
printf("%d\n",fbi(i));
return 0;
}
总结:
递归定义:我们把一个直接调用自己或通过一系列的调用语间接的调用自己的函数,称作递归函数;
注:每个递归定义必须有至少一个条件,当满足该条件时不再继续调用。而是返回值退出。
四则运算
后缀表达式的计算问题
看我另外一片博客中的题目“后缀表达式”,传送门。
中缀表达式转后缀表达式
规则:
从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,判断其与栈顶符号的优先级,若为右括号或者优先级不高于栈顶符号,则栈顶元素依次出栈并输出,将该符号入栈,直到最终输出后缀表达式为止。
队列
定义
定义:队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
队列是一种先进先出的线性表,允许插入的一端称为队尾,允许删除的一段称为队头。
循环队列
定义:我们把队列这种头尾相接的顺序储存称为循环队列
如何判断队列是满还是空呢
1.设置一个标志变量flag;
2.空出一个元素 则此时判断队列满的条件是
(rear+1)%queuesize==front;//我们一般采用这个
结构
//顺序储存的队列结构体
typedef struct int qselemtype;//视具体情况而定
typedef struct{
qseletype data[maxsize];
int rear; //队尾
int front; //队头
}sqqueue;
初始化空队列
//初始化空队列q
status creatqueue(sqqueue *q)
{
q->front=0;
q->rear=0;
return ok;
}
返回队列长度
//求循环队列的队列长度
int lengthqueue(sqqueue q)
{
return ((q->rear-q->front+maxsize)%maxsize);
}
入队
//入队
status inqueue(sqqueue *q,qseletype e)//若队列没有满则将元素e插入到队尾
{
if((q->rear+1)%maxsize==q->front)
return error;
q->data[q->rear]=e;
q->rear=(q->rear+1)%maxsize;
return ok;
}
出队
//出队
status outqueue(sqqueue *q,qselemtype *e)//若队列不为空,则删除队头,并赋值给e
{
if(q->rear==q->front)//判断队列是否为空
return error;
e=q->data[q->front];
q->front=(q->front+1)%maxsize;
return ok;
}
链式储存
注:由于链表的尾部只方便插入而不方便删除,所以将表为计为队尾,表头对于插入删除都方便,可计为队头。
结构
//结点的结构
typedef struct qnode{
qelemtype data;
struct qnode *next;
}qnode,*queueptr;
//链队列结构
typedef struct linkqueue
{
queueptr front,rear;//头尾指针
};
入队
//入队
status inqueue(linkqueue *q,qseletype e)
{
queueptr t=(queueptr)malloc(sizeof(qnode));
if(!s) //储存分配失败
exit(OVERFLOW) ;//强制退出
t->data=e;
t->next=NULL;
//将t插入到队尾
q->rear->next=t;
//将队尾设置成t
q->rear=t;
return ok;
}
出队
//出队
status outqueue(linkqueue *q,qelemtype *e)//若队列不为空,则删除队头,并将其赋值给e
{
queueptr p;
if(q->front==q->rear)//空
return error;
//将第一个结点的元素给e
e=q->front->netx->data;
p=q->front->next;
q->front->next=q->front->next->next;
if(q->rear==p) //删除之后为空
q->rear=q->front;
free(p);
return ok;
}