第三章总结
栈与队列都是特殊的限制型的线性表,通常没有查询这个操作
栈的特点就是先进后出,只可以在栈顶进行插入删除,顺序栈定义指向栈顶与栈底的指针(方便判断栈的情况)也可以只定义一个栈顶指针top然后通过top-1来判断栈顶是否有元素进而判断整个栈的情况,应注意栈顶指针是最后一个元素的下一个,入栈出栈要注意判断栈空栈满的情况。
链栈与链表的操作差不多,初始化,入栈出栈比较方便,入栈不用判栈满,但出栈应注意判断栈空的情况。
递归是在函数,过程或者数据结构定义时直接或间接出现定义本身的应用,应该理清内存的运行情况,递归实际用于数学函数(阶乘),数据结构(节点定义时用了自己的类型的指针),问题解决(汉诺塔这个我还是不太明白)。递归是用一个工作栈来存储活动记录,在函数F1内调用了函数F2时就会把函数F1的实参+返回地址+F2的局部变量打包放入栈中,以此类推。递归结构比较清晰但是时间(生成工作记录及出入栈)与空间(工作栈)消耗大,也要考录栈满的情况,所以看情况可以用循环语句(迭代)来代替递归。
队的特点是先进先出,队尾进队头出
顺序队列为了防止出现假溢出的情况而浪费了内存空间,就用取模的方法实现循环队列,每次对头尾指针的操作都应该取模(这个我还需要时间去消化一下)。
链队是只需要一个头节点,一个头指针与一个尾指针因为是队尾进队头出,出队时应该注意判断栈空的情况并释放队头的空间
作业:括号匹配与银行排队
关于括号匹配的问题我是用了好几种方法
一:顺序栈来实现,用getchar()一个一个字符读入
#include <iostream>
#include <stdio.h>#include <stdlib.h> using namespace std;typedef struct{ char data[100]; int top;}sqlist;int main(){ sqlist *l; l=(sqlist *)malloc(sizeof(sqlist)); l->top=0; char ch; while((ch=getchar())!='\n') { if(ch==')'&&l->top>0&&l->data[l->top-1]=='(') //若为)则判断栈顶是否为空,栈顶不为空就指针下移判断是否匹配 l->top--; //指针下移 else if(ch==']'&&l->top>0&&l->data[l->top-1]=='[') l->top--; else if(ch=='}'&&l->top>0&&l->data[l->top-1]=='{') l->top--; else if(ch=='('||ch=='{'||ch=='[') l->data[l->top-1]=ch; //若是左符号就入栈 } if(l->top==0) //如果全部匹配 cout<<"Yes"; else cout<<"No"; return 0;}在拼题啊上显示time limited ……
原因可能有 :
1.没有循环的终止条件
2.程序调用超时3.算法优化问题检查了一下发现有循环的条件(因为在DEV上是可以运行的)所以应该就是算法优化性的问题了,于是去参考了一些网上的资源就发现了DTL这么一个神奇的东西
二:用stl的栈,用gets()读取
#include<iostream>
#include<stack>//用的是stl的栈 #include<cstring>#include<cstdio>using namespace std;int col(char x)//判断同一类型的符号 { if(x=='('||x==')') return 1; if(x=='['||x==']') return 2; if(x=='{'||x=='}') return 3;}int main(){ char ch[100]; stack<char> sqlist;//定义了一个字符型的栈while(gets(ch)!=NULL)
{ int len=strlen(ch);//取一行并计算长度 int flag=0; for(int i=0;i<len;i++) { if(sqlist.empty()&&(ch[i]==')'||ch[i]=='}'||ch[i]==']')) {//如果栈 flag=1; break; } else if(ch[i]=='('||ch[i]=='{'||ch[i]=='[') sqlist.push(ch[i]); //如果字符为左边就入栈 else if(ch[i]==')'||ch[i]=='}'||ch[i]==']') {//如果字符为右边类型的并且并且与栈顶的元素是同一种字符类型即配对就出栈 if(col(ch[i])==col(sqlist.top())) sqlist.pop(); } else {//如果 flag=1; break; } } if(flag==1&&sqlist.empty()) cout<<"yes"; else cout<<"no"; } return 0;}最后写出的程序可以在DEV上实现而在拼题啊上会显示GETS函数没有定义但明明已经加了他的头文件stdio.h后来百度才知道这个函数原本是C语言中的函数在拼题啊上是过不了的,于是想着说可以把代码改成C语言的但是发现也不行,因STL只适用与C++所以唯一的解决方法就是换一个同样可以读取一行的函数
STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来,
STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模版函数的方式,这相比于传统的由函数和类
组成的库来说提供了更好的代码重用机会。在C++标准中,STL被组织为下面的13个头文件:<algorithm>、<deque>、<functional>、<iterator>、<vector>、<list>、<map>、
<memory>、<numeric>、<queue>、<set>、<stack>和<utility>。
定义:stack<int> s;
入栈:s.push(3);出栈:s.pop();判空:s.empty();取大小:s.size();#include <iostream>
#include <stack> using namespace std;int main()
{ stack<int> s;s.push(1);s.push(5);s.push(7);cout << s.size() << endl;while(!s.empty()){ cout << s.top() << " ";s.pop();}return 0;}输出
3
7 5 1由于第一次的代码是用getchar函数写的,一个字符地读取,第二次的是用gets读取一行字符
关于getchar()
当我们从键盘输入字符‘1’,‘2’,并按下回车后,我们的输入被放入了输入缓冲区,这个时候getchar()会从缓冲区中读取我们刚才的输入,一次只读一个字符,所以字符1就被拿出来了,赋值给了c,然后putchar()又将c放在了标准输出,同时字符‘1’也被缓冲区释放了,而字符‘2’仍然被留在了缓冲区。而这样是很不安全的,有可能下次使用的时候,我们的缓冲区会读到一些垃圾,但是当程序结束的时候,它会自动刷新。ch=getchar()!='\n'getchar()会从输入缓冲区去读取内容,也就是说我们把所有的内容都输入完成并且按下了Enter键后,我们的输入才被送进去了输入缓冲区,这个时候,while循环才开始工作,每一次getchar()从输入缓冲区读取一个字符,然后如果不是换行符就输出。
gets()
gets函数的头文件是stdio.h原型如下: char *gets(char *s); gets从stdin中读入一行内容到s指定的buffer中,当遇到换行符或EOF时读取结束。读取成功时,返回s地址;失败时返回null。需要注意的是,gets会将行末尾的’\n’字符或EOF替换成’\0’,这样,gets读取的内容中不包括’\n’字符。如果要获取读取字符串的长度,可以调用strlen函数获得。
getline ()
对于C++语言,如果使用C字符串的话,就采用cin.getline()函数,如果采用string型字符串的话,就采用全局函数getline(cin,n);注意,这两个函数都不读入最后的换行符。
于是我又重新换了用cin.getline来写
#include<iostream>
#include<stack>//用的是stl的栈 #include<cstring>#include<cstdio>using namespace std;int col(char x)//判断同一类型的符号 { if(x=='('||x==')') return 1; if(x=='['||x==']') return 2; if(x=='{'||x=='}') return 3;}int main(){ char ch[100]; stack<char> sqlist;//定义了一个字符型的栈cin.getline(ch,100);
int flag=0; for(int i=0;i<100;i++) { if(sqlist.empty()&&(ch[i]==')'||ch[i]=='}'||ch[i]==']')) {//如果栈空 flag=1; break; } else if(ch[i]=='('||ch[i]=='{'||ch[i]=='[') sqlist.push(ch[i]); //如果字符为左边就入栈 else if(ch[i]==')'||ch[i]=='}'||ch[i]==']') {//如果字符为右边类型的并且并且与栈顶的元素是同一种字符类型即配对就出栈 if(col(ch[i])==col(sqlist.top())) sqlist.pop(); } else {//如果 flag=1; break; } } if(flag==1&&sqlist.empty()) cout<<"yes"; else cout<<"no"; return 0;}
提交显示最长字符串的问题 stl加cin.getline,这个用cin.getline应该是没问题的呀可是为什么还是不对呢
三:
#include<iostream>
using namespace std;typedef char elemtype;
typedef struct stacknode{ elemtype data; struct stacknode *next;}stacknode,*linkstack; //linkstack*错void push(linkstack &,elemtype); //把E入栈
elemtype pop(linkstack &); //出栈并返回栈顶元素 bool empty(linkstack ); //判断栈是否为空返回true/falseint main()
{ string ch; linkstack s=NULL; //初始化一个空栈 int i=0,flag=1; cin>>ch; while(ch[i]!='\0'&&flag) //当还未出现未匹配并且未还没到最后一个元素 { if(ch[i]=='('||ch[i]=='{'||ch[i]=='[') push(s,ch[i]); //如果为左符号就入栈 else if(ch[i]==')'||ch[i]=='}'||ch[i]==']') {//如果栈空(没有左符号或前面的已经全部匹配)且当前元素为右符号 if(!empty(s)) { flag=0; break; //跳出整个循环,判断结束 } else if(!((ch[i]==')'&&pop(s)=='(')||(ch[i]=='}'&&pop(s)=='{')||(ch[i]==']'&&pop(s)=='['))) { flag=0; break; } } i++; //继续扫描下一个元素 } if(!empty(s)&&flag) //如果栈空(全部配对)且不存在不匹配的两种情况 cout<<"yes"; else cout<<"no"; return 0;}void push(linkstack &s,elemtype e)
{ //把E入栈 stacknode *p=new stacknode; p->data=e; p->next=s; //s=NULL s=p;}elemtype pop(linkstack &s){ //出栈栈顶元素并用H返回 elemtype h; if(s!=NULL) { //如果栈非空时 h=s->data; stacknode *p=s; s=s->next; delete p; return h; }}bool empty(linkstack s){ //判断栈空,空为false if(s==NULL) return false; else return true;}这种写法我觉得是没问题的但是不论是哪种输入都是显示no,不知道为什么
我在问了老师之后我重新改了一下把如果是右符号再分情况判断栈空与非空的情况
#include<iostream>
using namespace std;typedef char elemtype;
typedef struct stacknode{ elemtype data; struct stacknode *next;}stacknode,*linkstack; //linkstack*错void push(linkstack &,elemtype); //把E入栈
elemtype pop(linkstack &); //出栈并返回栈顶元素 bool empty(linkstack ); //判断栈是否为空返回true/falseint main()
{ string ch; linkstack s=NULL; //初始化一个空栈 int i=0,flag=1; cin>>ch; while(ch[i]!='\0'&&flag) //当还未出现未匹配并且未还没到最后一个元素 { if(ch[i]=='('||ch[i]=='{'||ch[i]=='[') push(s,ch[i]); //如果为左符号就入栈 else if(ch[i]==')'||ch[i]=='}'||ch[i]==']') {//如果栈空(没有左符号或前面的已经全部匹配)且当前元素为右符号 if(!empty(s)) { flag=0; break; //跳出整个循环,判断结束 } else if(!((ch[i]==')'&&pop(s)=='(')||(ch[i]=='}'&&pop(s)=='{')||(ch[i]==']'&&pop(s)=='['))) { flag=0; break; } } i++; //继续扫描下一个元素 } if(!empty(s)&&flag) //如果栈空(全部配对)且不存在不匹配的两种情况 cout<<"yes"; else cout<<"no"; return 0;}void push(linkstack &s,elemtype e)
{ //把E入栈 stacknode *p=new stacknode; p->data=e; p->next=s; //s=NULL s=p;}elemtype pop(linkstack &s){ //出栈栈顶元素并用H返回 elemtype h; if(s!=NULL) { //如果栈非空时 h=s->data; stacknode *p=s; s=s->next; delete p; return h; }}bool empty(linkstack s){ //判断栈空,空为false if(s==NULL) return false; else return true;}提交显示还是最长字符串的问题 自定义栈函数加string
cin遇到空格,tab键就会结束输入(并且会忽略)所以遇到空格就已经停止输入了,所以就会显示出错
getline(cin,ch)就可以了(空格,ta键会像普通字符一样赋值给ch,遇到换行符结束,并且会丢弃换行符)
getline(cin, str, '~')getline新增加了一个参数,是字符类型的,表示终止符,遇到该终止符结束输入,并且不会丢弃换行符,getline函数位于命名空间std中
四:用了书本上的方法用switch
#include<iostream>
using namespace std;typedef char elemtype;
typedef struct stacknode{ elemtype data; struct stacknode *next;}stacknode,*linkstack; //linkstack*错void push(linkstack &,elemtype); //把E入栈
void pop(linkstack &,elemtype &); //出栈并返回栈顶元素 elemtype gettop(linkstack); //得栈顶元素用来比较int main()
{ elemtype ch[100]; elemtype e; linkstack s=NULL; //初始化一个空栈 int flag=1; cin.getline(ch,100); for(int i=0;i<100;i++) { switch(ch[i]) { //如果为左符号就入栈并跳出switch进行下一次的扫描 case '(': case '[': case '{': push(s,ch[i]); break; case ')': //如果为)就判断栈是否为空,若不为空就得栈顶元素出来比较 if(s!=NULL&&gettop(s)=='(') pop(s,e); //若栈非空且匹配则出栈 else flag=0; //否则就跳出本次的switch break; case ']': //如果为】就判断栈是否为空,若不为空就得栈顶元素出来比较 if(s!=NULL&&gettop(s)=='[') pop(s,e); else flag=0; break; case '}': //如果为}就判断栈是否为空,若不为空就得栈顶元素出来比较 if(s!=NULL&&gettop(s)=='{') pop(s,e); else flag=0; break; } } if(s==NULL&&flag) //如果栈空且flag不变则匹配 cout<<"Yes"; else cout<<"No"; return 0;}void push(linkstack &s,elemtype e)
{ //把E入栈 stacknode *p=new stacknode; p->data=e; p->next=s; //s=NULL s=p;}void pop(linkstack &s,elemtype &e){ //出栈栈顶元素并用H返回 if(s!=NULL) { //如果栈非空时 e=s->data; stacknode *p=s; s=s->next; delete p; }}elemtype gettop(linkstack s){ //得栈顶元素 if(s!=NULL) return s->data;}提交显示答案错误,一直在想为什么,最后才发现是因为输出yes no是不用大写的,真的是头疼,最后还是提交成功了
括号问题解决了(虽让用了两个星期)
说说银行排队问题,这个反而比较简单些
#include <iostream>
using namespace std;int main(){ int a[1100],b[1100],n,num,j=0,k=0,la,lb; cin>>n; for(int i=0;i<n;i++) {//输入两个数组的元素,奇数在A数组,偶数在B数组 cin>>num; if(num%2!=0) { a[j++]=num; } if(num%2==0) { b[k++]=num; } }//最后的J,K为两个数组的元素个数,不是最后一个的下标哦 la=0; lb=0; while(j>0&&k>0)//两个数组都非空时 { for(int i=0;i<2;i++) {//输出A数组的两个 cout<<a[la++]; if(n!=1)//如果当前的数不是最后一个数就输出空格 { cout<<" "; } j--; n--;//A数组及总的元素个数都减一 } for(int i=0;i<1;i++) {//输出一个B数组的元素 cout<<b[lb++]; if(n!=1)//如果当前的元素不是最后一个就输出空格 { cout<<" "; } k--; n--;//B数组及总的元素个数都减一 } } while(j>0)//输出A数组剩下的元素 { cout<<a[la++];//la一直用来记录A数组的输出情况 if(j!=1) { cout<<" ";//如果当前的元素不是A数组的最后一个元素就接着输出空格 } j--;//A数组个数减一 } while(k>0) {//同A数组的操作一致 cout<<b[lb++]; if(k!=1) { cout<<" "; } k--; } return 0;}这个也是遇到了一点问题后来检查才发现是因为当有个数组到头时应该把另一个数组输出时写错成了if而不是while