目录
1.问题描述
2.需求分析
3.算法设计和实现
4.调试分析与测试结果
1.问题描述
标准Web浏览器具有在最近访问的网页间后退和前进的功能。实现这些功能的一个方法是:使用两个栈,追踪可以后退和前进而能够到达的网页。在本题中,要求模拟实现这一功能。
2.需求分析
BACK:将当前页面压入前向堆栈的顶部;从后向堆栈的顶部弹出该页,使其成为新的当前页。如果后向堆栈为空,则该指令忽略。
FORWARD:将当前页面压入后向堆栈的顶部;从前向堆栈的顶部弹出该页,使其成为新的当前页。如果前向堆栈为空,则该指令忽略。
VISIT:将当前页面压入后向堆栈的顶部,将URL指定为新的当前页。前向堆栈被清空。
QUIT:退出浏览器。
假设浏览器最初在网址http://www.game.org/上加载网页。
3.算法设计和实现
设计思路:
围绕栈和队列的操作展开,通过栈和队列的结构来保存用户的历史记录和输出记录,并根据用户的操作更新数据结构和输出结果。定义了栈结构体ST和队列结构体QU,分别用于保存用户的历史记录和输出记录。实现了入队函数PUSHQ和出队函数POPQ,用于对队列进行入队和出队操作。实现了入栈函数PUSH和出栈函数POP,用于对栈进行入栈和出栈操作。实现了判空函数EMPTY,用于判断栈是否为空。实现了回溯操作函数BACK,将当前访问的网页保存在前向栈stfront中,从回溯栈strear弹出上一次访问的网页,并将其作为当前网页,将当前网页入队。实现了前进操作函数FORWARD,将当前访问的网页保存在回溯栈strear中,从前向栈stfront弹出下一次访问的网页,并将其作为当前网页,将当前网页入队。实现了访问操作函数VISIT,将当前访问的网页保存在前向栈stfront中,并将当前网页入队。在主函数main()中,首先初始化栈、队列和起始网页cur。然后根据用户的输入进行不同的操作,包括访问、回退、前进和退出。根据输入的操作类型,调用相应的函数进行处理并更新cur和输出队列qu。最后输出历史访问记录。
//主要函数:
void PUSHQ(QU *qu, char cur[])//入队
void POPQ(QU *qu)//出队
void PUSH(ST *st, char cur[])//入栈
void POP(ST *st)//出栈
int EMPTY(ST *st)//判空
void BACK(ST *stfront,ST *strear,char cur[], QU *qu)//回溯
void FORWARD(ST *stfront, ST *strear, char cur[], QU *qu)//前寻
void VISIT(ST *stfront,ST *strear, char cur[],QU *qu)//访问
//源代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct stack
{
char s[100][70];
int top;
}ST;//栈定义
typedef struct queue
{
char q[100][70];
int head;
int tail;
}QU;//队列定义,用于接受输出
void PUSHQ(QU *qu, char cur[])//入队
{
if (qu->tail == 100)
{
printf("队满\n");
}
else
{
qu->tail++;
strncpy(qu->q[qu->tail], cur,strlen(cur) + 1);
}
}
void POPQ(QU *qu)//出队
{
qu->head++;
}
void PUSH(ST *st, char cur[])//入栈
{
if (st->top == 100)
{
printf("栈满\n");
}
else
{
strncpy(st->s[st->top],cur,strlen(cur)+1);
st->top++;
}
}
void POP(ST *st)//出栈
{
if (st->top == 0)
{
printf("栈空\n");
}
else
{
st->top--;
}
}
int EMPTY(ST *st)//判空
{
if (st->top == 0)
return 1;
else
return 0;
}
void BACK(ST *stfront,ST *strear,char cur[], QU *qu)//回溯
{
if (!EMPTY(strear))
{
PUSH(stfront, cur);
POP(strear);
strncpy(cur,strear->s[strear->top],strlen(strear->s[strear->top]) + 1);
PUSHQ(qu, cur);
}
else
{
char *a = "Ignored";
PUSHQ(qu, a);
}
}
void FORWARD(ST *stfront, ST *strear, char cur[], QU *qu)//前寻
{
if (!EMPTY(stfront))
{
PUSH(strear, cur);
POP(stfront);
strncpy(cur,stfront->s[stfront->top],strlen(stfront->s[stfront->top]) + 1);
PUSHQ(qu, cur);
}
else
{
char *a = "Ignored";
PUSHQ(qu,a);
}
}
void VISIT(ST *stfront,ST *strear, char cur[],QU *qu)//访问
{
PUSHQ(qu, cur);
stfront->top = 0;
}
int main()
{
printf("输入:\n");
ST stfront;
ST strear;
stfront.top = 0;
strear.top = 0;
QU qu;
qu.head = -1;
qu.tail = -1;
char cur[70];
char start[70] = "http://www.acm.org/";//需先对此网站进行如回溯栈的特殊处理
char in[2][70];
strncpy(cur, start,strlen(start) + 1);
scanf("%s", in[0], 70);
while (strcmp(in[0], "QUIT") != 0)
{
if (strcmp(in[0], "VISIT") == 0)
{
PUSH(&strear, cur);
scanf("%s", in[1], 70);
strncpy(cur,in[1],strlen(in[1])+1);
VISIT(&stfront, &strear, cur, &qu);
}
else if (strcmp(in[0], "QUIT") == 0)
{
break;
}
else if (strcmp(in[0], "BACK") == 0)
{
BACK(&stfront, &strear, cur, &qu);
}
else
{
FORWARD(&stfront, &strear, cur, &qu);
}
scanf("%s", in[0], 70);
}
printf("输出:\n");//输出
while (qu.head != qu.tail)
{
POPQ(&qu);
printf("%s\n", qu.q[qu.head]);
}
return 0;
}
4.调试分析与测试结果
调试分析:
问题1:strcpy函数在Microsoft Visual C++ 6.0调试中报错
解决方法:选用strncp函数,其相较于strcpy函数的优点就是strncpy函数可以选择复制多大的字符串,可以有效的避免第一个指针分配的内存大小太小,可以只选择需要的数据进行复制。
问题2:相关的栈和队列函数(PUSH()、POP()、EMPTY()、PUSHQ()、POPQ()等)在调用时传递的参数有问题。
解决方法:检查对应传参值,确保传参正确,检查入栈和入队时,是否将字符串正确地复制到相应的数组中。
测试结果: