您的位置:首页 > 理论基础 > 数据结构算法

链栈的实现并解决行编辑程序问题及问题总结

2017-03-11 19:57 393 查看
1、栈的链式存储结构,也称为链栈,是一种限制操作的链表,即规定链表中的插入和删除操作只能在链表开头进行,链栈的实现与链表的实现基本相同,头结点作为栈顶位置。链栈结构如图:



        top 为栈顶指针,始终指向当前栈顶元素前面的头结点,若top->next=NULL,则代表空栈。链栈在使用完毕时,要释放其空间,避免内存泄漏。

2、行编辑程序问题:在用户输入一行的过程中,允许用户输入出差错,并在发现有误时可以及时更正。

         解决方法:设立一个输入缓冲区,用以接收用户输入的一行字符,然后逐行存入用户数据区,并假设“#”为退格符,“@”为退行符。

         例:假设从终端接受了这样两行字符:

                   whli##ilr#e(s#*s)

                   outcha@putchar(*s=#++);

                   则实际有效的是下列两行:

                   while(*s)

                   putchar(*s++);

链栈的实现并用其解决行编辑程序问题,代码如下:

#include <stdio.h>
#include <stdlib.h>
#define ELEMTYPE char

typedef struct SNode
{
ELEMTYPE data;         // 数据域
struct Snode *next;     // 链域
}*LinkStack;

// 链栈的初始化
LinkStack InitStack()
{
LinkStack S = (LinkStack)malloc(sizeof(struct SNode));
S->next = NULL;
return S;
}

// 判栈空
int IsEmpty(LinkStack S)
{
if(S->next == NULL)
{
return 1;
} else
{
return 0;
}
}

// 压栈
int Push(LinkStack top, ELEMTYPE x)
{
LinkStack temp = (LinkStack)malloc(sizeof(struct SNode));
if(!temp)
{
printf("分配失败!\n");
return 0;
} else
{
temp->data=x;
temp->next=top->next;         // 不可少,少了不成链
top->next=temp;
return 1;
}
}

// 弹栈
int Pop(LinkStack top, ELEMTYPE *x)
{
LinkStack temp;
temp = top->next;
if (temp == NULL)
{
printf("栈已空,无法弹栈!\n");
return 0;
} else
{
top->next = temp->next;             // 不可少,少了不成链
*x=temp->data;
free(temp);
return 1;
}
}

// 链栈的清空
void ClearStack(LinkStack S)
{
LinkStack temp;
while(S->next)
{
temp = S->next;
S->next = temp->next;
}
}

// 链栈的销毁
void DestroyStack(LinkStack S)
{
LinkStack temp;
while(S->next)
{
temp = S;
S=S->next;
free(temp);
}
free(S);
}

// 行编辑问题
void LineEdit(LinkStack S)
{
ELEMTYPE c, ch;
int i;
ch=getchar();
while(ch!=EOF)					  // 文件结束符(end of file),Windows下ctrl+Z表示EOF
{
ELEMTYPE s[100]={0};         // 声明的时候进行初始化,作为清空语句把垃圾内存清理成'\0',也就是0x00(0)。可滤掉乱码
while(ch!='\n')
{
switch(ch)
{
case '#':
if(!IsEmpty(S))
Pop(S, &c);
break;
case '@':
ClearStack(S);
break;
default:
Push(S, ch);
break;
}
ch = getchar();
}
printf("输入的有效内容为:\n");
for (i=0; !IsEmpty(S); ++i)
{
Pop(S, &c);
s[i] = c;
}
for (i=strlen(s)-1; i>=0; --i)		// 利用数组将有效内容正序输出
printf("%c", s[i]);
printf("\n");
ClearStack(S);
ch=getchar();
}

}

int main()
{
LinkStack S = InitStack();
LineEdit(S);
DestroyStack(S);

return 0;
}
运行结果如图:



在程序实现过程中出现的问题,总结如下:

1)、Push函数里temp->next=top->next;  Pop函数里top->next =temp->next; 这两句并不多余,相反还很重要,缺少了哪一句,链栈都不能成链,结果也是错误的。

2)、getchar函数的用法:getchar有一个int型的返回值,当程序调用getchar时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中)。当用户键入回车之后,getchar才开始从stdin流中每次读入一个字符,getchar函数的返回值是用户输入的第一个字符的ASCII码,如出错返回-1,且将用户输入的字符回显到屏幕,如用户在按回车之前输入了不止一个字符,其他字符会保留在键盘缓存区中,等待后续getchar调用读取。也就是说,后续的getchar调用不会等待用户按键,而是直接读取缓冲区中的字符,直到缓冲区中的字符读完为后,才等待用户按键。getchar函数的功能是从键盘上输入一个字符。其一般形式为:
getchar();, 通常把输入的字符赋予一个字符变量,构成赋值语句。注意:getchar函数只能接受单个字符,输入数字也按字符处理。输入多于一个字符时,只接收第一个字符;使用本函数前必须包含文件<stdio.h>。getchar();的用法很多:一种是清空回车符,这种情况一般发生在在循环中涉及到输入的情况;还有一种是某些编译平台(IDE)在运行程序时并没有在程序运行后给人看结果的时间(也就是闪退),这时候在程序末尾加上getchar()就能造成程序的暂停,留给程序员看结果的机会。

3)、起初在外层while循环外声明数组s[],结果运行程序,测试几行字符串后,前几个输出还挺正常,后面的会出现乱码现象。这是因为字符串输出前没使用清空语句把垃圾内存清理成’\0’,也就是0x00(0),可以在声明的时候进行初始化为{0},所以把数组的声明初始化放在外层while循环里面,这样每次进入内层while循环之前就会清空垃圾内存,滤掉乱码,这是C语言的习惯。

4)、链栈的清空操作,不能用free,free掉就是将申请的内存还回去了,之后就无法再使用了,链栈的清空就是使栈顶指针指向表头就好了,原先压入的数据清不清除效果都一样。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐