data structure——栈和队列
栈和队列的特点是:栈(stack)是先进后出,而队列是先进先出。
栈的不同形式的定义:
- 顺序栈的定义:
1
2
3
4
5typedef struct
{
int data[maxsize]; //存放栈中元素
int top; //注意这是栈顶指针,这个指针是用来指数组中的元素的,不是在结点中的指针域
} - 链栈结点定义:(即用链表来存储栈)
1
2
3
4
5typedef struct LNode
{
int data; //数据域
struct LNode *next; //指针域
}LNode;
顺序栈的一些操作:
初始化栈
1
2
3
4void initStack(SqStack &st)
{
st.top=-1; //栈顶指针设置为-1
}或者可以简写:
int stack[maxsize-1];int top==-1;
判断栈空
1
2
3
4
5
6
7int isEmpty(SqStack st)
{
if(st.top==maxsize-1)
return 1;
else
return 0;
}进栈
1
2
3
4
5
6
7
8int push(SqStack &st,int x)
{
if(st.top==-1)
return 0;
++(st.top);
st.data[st.top]=x;
return 1;
}或者也可以简写:
stack[++top]=x;
出栈
1
2
3
4
5
6
7
8int pop(SqStack &st, int x)
{
if(st.top==-1)
return 0;
x=st.data[st.top];
--(st.top);
return 1;
}或者也可以简写:
x=stack[top--];
链栈的一些操作:
- 初始化链栈
1
2
3
4
5void initStack(LNode *&lst)
{
lst=(LNode* )malloc(sizeof(LNode)); //制造一个头结点
lst->next=NULL;
} - 判断栈空
1
2
3
4
5
6
7int isEmpty(LNode *lst)
{
if(lst->next=NULL)
return 0;
else
return 1;
} - 进栈操作
1
2
3
4
5
6
7
8
9void push(LNode *lst,int x)
{
LNode *p;
p=(LNode *)malloc(sizeof(LNode));
p->next=NULL;
p->data=x;
p->next=lst->next;
lst->next=p;
} - 出栈操作
1
2
3
4
5
6
7
8
9
10
11void pop(LNode *lst, int &x)
{
LNode *p;
if(lst->next==NULL)
return 0;
p->next=lst->next;
p->data=x;
lst->next=p->next;
free(p);
return 1;
}
队列的不同形式的定义:
- 顺序队列的定义:
1
2
3
4
5
6typedef struct
{
int data[maxsize]; //用一个数组存储数据
int front; //队首指针
int rear; //队尾指针
}sqQueue; - 链队定义:
队结点类型定义:链队类型定义:1
2
3
4
5typedef struct QNode
{
int data; //数据域
struct QNode *next; //指针域
}QNode;1
2
3
4
5typedef struct
{
QNode *front; //队头指针
QNode *rear; //队尾指针
}LiQueue;
循环队列的一些操作:
- 初始化
1
2
3
4void initQueue(SqQueue &qu)
{
qu.front=qu.rear=0;
} - 判断队空:
1
2
3
4
5
6
7void isQueueEmpty(sqQueue qu)
{
if(qu.rear=qu.front)
return 1;
else
return 0;
} - 进队:
1
2
3
4
5
6
7
8
9
10
11void enQueue(sqQueue &qu,int x)
{
if((qu.rear+1)%maxsize==qu.front)
return 0;
else
{
qu.rear=(qu.rear+1)%maxsize;
qu.data[qu.rear]=x;
return 1;
}
} - 出队:
1
2
3
4
5
6
7
8
9
10
11void deQueue(sqQueue &qu,int x)
{
if(qu.front==qu.rear)
return 0;
else
{
qu.front=(qu.front+1)%maxsize;
x=qu.data[qu.front];
return 1;
}
}
链队的一些操作:
- 初始化
1
2
3
4
5void initQueue(LiQueue *&lqu)
{
lqu=(LiQueue *)malloc(sizeof(LiQueue));
lqu->front=lqu->rear=NULL;
} - 判断队空
1
2
3
4
5
6
7int isQueueEmpty(LiQueue *lqu)
{
if(lqu->front==NULL||lqu->rear==NULL)
return 1;
else
return 0;
} - 入队
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void enQueue(LiQueue *lqu,int x)
{
QNode *p; //指针p是另一个结构体而来的
p=(QNode *)malloc(sizeof(QNode));
p->data=x;
p->next=NULL;
if(lqu->rear==NULL)
lqu->front=lqu->rear=p;
else
{
lqu->rear->next=p; //将新节点连接至队尾,rear指向它
lqu->rear=p;
}
} - 出队
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15void deQueue(LiQueue *lqu ,int &x)
{
QNode *p;
if(lst->rear=NULL)
return 0;
else
p=lst->front;
if (lqu->front==lqu->rear)
lqu->front=lqu->rear==NULL;
else
lqu->front=lqu->front->next;
x=p->data;
free(p);
return 1;
}
应用
- 顺序栈的应用
1.设计一个算法,判断一个表达式中的括号是否正确的配对,表达式已经存入字符数组exp[]
中,表达式中的字符个数是n
。
1 | int match(char exp[],int n) |
此列题很好的说明了栈是一种有效处理”先进后出”的一种数据类型,也就是说,当以后遇到一种问题,在处理问题的过程中如果出现了一个子问题,那么先解决了这个子问题再来处理这个问题的处理思路可以使用栈这个模型去解决问题。
2.编写一个函数,求后缀式的数值,其中后缀式存于一个字符数组exp
中,exp
中最后一个字符为\0
,作为结束符,并假设后缀式中的数字都只有一位。(出现的除法的结果都按一位存储)
1 | int jisuan(int a,char jisuan,int b) |
3.用不带头结点的单链表存储链栈,设置初始化栈,判断栈是否为空,进栈和出栈等相应的算法
1 | void initStack1(LNode *&lst) //初始化栈 |
下面是例题:
1.顺序栈s0
和s1
共享了一个存储区elem[0,1,..,maxsize-1]
。是设计共享栈s0
,s1
以及有关共享栈的入栈和出栈操作的算法,假设元素为int
型。
1 | typedef struct //结构体定义 |
2.利用两个站s1
,s2
来模拟一个队列,假设栈中的元素为int
型,栈中元素最多为maxsize
。已知栈的3
个运算定义如下:push(ST,x)
:元素x
入st
栈pop(ST,&x)
:st
栈顶元素出栈,赋给元素x
isEmpty(ST)
:判断st
栈是否为空
如何利用栈的运算来实现队列的3
个运算,(元素入队列)enQueue
,(元素出队列)deQueue
,(判断栈是否为空)isQueueEmpty
。
1 | int enQueue(sqstack &s1,sqstack &s2,int x) |
其实本题其实主要的工作是将栈的”先进后出”的特性变为”先进先出”。
3.假设一I
,O
分别表示入栈和出栈的操作,写出一个算法,判定给出的操作序列是否合法,若合法则返回1
否则返回0
假定被判定的操作序列已经存入一维数组ch[]
中,操作序列以“\0
”为结束符。
1 | int judge(char[]) |
4.假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾结点,但不设头指针,请写出相应的入队和出队的算法。
1 | void enQueue(LNode *&rear,int x) |
5.如果允许在循环队列的两端都可以进行插入和删除操作,要求:写出循环队列的类型定义,写出从队尾删除和从对头插入的算法。
1 | typedef struct |
6.设计一个循环队列,用front
和rear
分别作为队头和队尾指针,用一个标志tag
表示队列是否为空当tag
为1
时队不空,为0
时表示为空。这样就可以用front==rear
来作为队满的条件。要求设计出队列的结构和相关的基本运算(队列元素为int
型)。
1 | typedef struct |
7.编写一个算法,将一个非负的十进制整数N
转换为一个二进制数。
1 | int BaseTrans(int N) |
8.试编写一个算法,检查一个程序中的花括号,方括号,小括号是否匹配,若全部匹配则返回1,否则就返回0.对于程序中出现的单引号和双引号不进行括号匹配。39
为单引号的ASCII
值,34
为双引号ASCII
值,单双引号出现必定成双出现。
1 | int pipeikuohao(char f[]) |