个人认为哈,这段代码是最近一个星期写的最完善的代码,如果我没有赋值错的话,应该一丢丢的问题都没错误,美观度其实还可以啦,如果不是单纯依靠函数的话,这个代码美观度可以很高很高
特别注意在151和159这几行代码有很强的复制率,但是我们并没有使用函数,是因为若使用函数我们会发现return?无法停止本层函数,这个是无法避免的重复
特别注意,原来的菜单函数那片一直犯了逻辑错误,导致并不能程序安全退出,这个是目前各种功能最完善的,原来的代码我又去看了一下,我发现我不想动内些代码了,越改越错。
#include<iostream>//内个注意一下下哈,链栈咋能有最大输入量的限制捏,所以不设MAX
#include<stdlib.h>
using namespace std;
typedef struct node
{
int data;
struct node *next;
}node;
typedef struct stack
{
node *head;//其实我想叫它头指针,那就叫它head吧
node *top;//其实这个我还想叫它p,这个这个这个。。。这不就是头插法的指针吗
int len;
}stack;
//注意一下,输出函数时都不要使用引用传递,因为你使用引用传递后会使得指针的指向方向发生变化 !!!
void menu(void);
void caidancaozuo(stack& S,int &jieguo);
void create(stack &S);//内个在顺序栈中创建的栈中我们设定的是可以直接输入元素的,但是在链栈中这个就算是单纯的初始化吧
void pankong(stack &S);//判断栈是否为空栈
void clean(stack &S);//个人认为清空和销毁之前创建插入和删除比较好
void destroystack(stack &S);
void outtop(stack S);//输出栈顶元素
void charu(stack &S);//插入栈顶元素
void deletetop(stack &S);//删除栈顶元素
void outstack(stack S);//输出栈的元素
void outlen(stack S);//输出栈的长度
int main(void)
{
stack liststack;
int jieguo=0;
menu();
caidancaozuo(liststack,jieguo);
if(jieguo==1)
{
return 0;
}
}
void menu(void)
{ //很经典的菜单形式
char a01[] = "(1)创建栈";
char a02[] = "(2)判断栈是否为空";
char a03[] = "(3)清空栈";
char a04[] = "(4)销毁栈";
char a05[] = "(5)输出栈顶元素";
char a06[] = "(6)用于插入栈顶元素";
char a07[] = "(7)删除栈顶个元素";
char a08[] = "(8)输出栈中所有元素";
char a09[] = "(9)输出长度";
char a10[] = "(10)出入任意不在前面菜单的数字将结束程序";
printf("%-50s", a01);
printf("%-50s\n", a02);
printf("%-50s", a03);
printf("%-50s\n", a04);
printf("%-50s", a05);
printf("%-50s\n", a06);
printf("%-50s", a07);
printf("%-50s\n", a08);
printf("%-50s", a09);
printf("%-50s\n", a10);
}
void caidancaozuo(stack& S,int &jieguo)//再次自我感觉良好觉得这个自我调用也不赖,放前边了
{
cout << "请问你想选择哪个指令" << endl;
int mingling;
cin >> mingling;
switch (mingling)
{
case 1:
{
create(S);
caidancaozuo(S,jieguo);
break;
}
case 2:
{
pankong(S);
caidancaozuo(S,jieguo);
break;
}
case 3:
{
clean(S);
caidancaozuo(S,jieguo);
break;
}
case 4:
{
destroystack(S);
caidancaozuo(S,jieguo);
break;
}
case 5:
{
outtop(S);//输出栈顶元素
caidancaozuo(S,jieguo);
break;
}
case 6:
{
charu(S);//插入栈顶元素
caidancaozuo(S,jieguo);
break;
}
case 7:
{
deletetop(S);//删除栈顶元素
caidancaozuo(S,jieguo);
break;
}
case 8:
{
outstack(S);//输出栈的元素
caidancaozuo(S,jieguo);
break;
}
case 9:
{
outlen(S);//输出栈的长度
caidancaozuo(S,jieguo);
break;
}
default:
if(mingling<=0||mingling>9)
{
jieguo=1;
}
cout << "您已经决定退出此程序,程序即将退出" << endl;
break;
}
}
void create(stack &S)
{
S.head=new node;
//cout<<"头指针是"<<S.head<<endl; 测试使用的
S.top=S.head;
S.head->next=NULL;//防止成为一个野指针(一定不要忘记这点哈)
S.len=0;
if(!S.head)
{
cout<<"不知神马原因未能成功创建此栈"<<endl;
return;
}
cout<<"已成功创建一个链栈"<<endl;
}
void pankong(stack &S)
{
if(!S.head)
{
cout<<"您还没有创建栈"<<endl;//一个判断是否为空的函数已经把有没有创建都考虑进去了,后期这些只需要调用这一个函数就足够
return ;//这个return管不到外边的函数
}
if(S.top==S.head)
{
cout<<"此栈是空栈"<<endl;
}else{
cout<<"此栈的长度是"<<S.len<<endl;
}
}
void charu(stack &S)//插入栈顶元素
{
//此函数其实就是头指针插入时的循环体中的代码
if(!S.head)//需要单独的写出来,因为pankong函数的return并不能使得我们的本函数退出,这个是无奈之举,不可封装函数
{
cout<<"您还没有创建栈,所以怎么操作"<<endl;
return ;
}
if(S.top==S.head)//特别注意在这几行代码有很强的复制率,大约7行左右,但是我们并没有使用函数,
{ //是因为若使用函数我们会发现return 无法停止本层函数,这个是无法避免的
cout<<"此栈是空栈"<<endl;
}
int x;
cout<<"请输入一个数字"<<endl;
cin>>x;
S.top=new node;//切记一定一定要给我们创建的值分配一个合理的位置。
S.top->data=x;
S.top->next=S.head->next;
S.head->next=S.top;
S.len++;
}
void clean(stack &S)
{
if(!S.head)//需要单独的写出来,因为pankong函数的return并不能使得我们的本函数退出,这个是无奈之举,不可封装函数
{
cout<<"您还没有创建栈,所以怎么操作"<<endl;
return ;
}
if(S.top==S.head)
{
cout<<"此栈是空栈"<<endl;
}
if(S.len==0)
{
cout<<"您的栈已经是空栈了哈,无需进行清空了"<<endl;
return;
}else{
int a=S.len;//因为后边S.len会发生变化,我们需要提前规避这个风险
for(int i=0;i<a;i++)
{
node *temp=S.top;
S.top=S.top->next;
free(temp);
S.len--;
}
S.top=S.head=NULL;
S.len=0;
cout<<"已经清空您的栈啦"<<endl;
return;
}
}
void deletetop(stack &S)//删除栈顶元素
{
//我觉得是不是在删除某个元素时先创建另一个量,使得这个量指向我们需要删除地址空间就好
if(!S.head)//需要单独的写出来,因为pankong函数的return并不能使得我们的本函数退出,这个是无奈之举,不可封装函数
{
cout<<"您还没有创建栈,所以怎么操作"<<endl;
return ;
}
if(S.top==S.head)
{
cout<<"此栈是空栈"<<endl;
}
node *temp=S.top;
S.top=S.top->next;
free(temp);
S.len--;
cout<<"栈顶元素已被删除"<<endl;
}
void destroystack(stack &S)//请注意销毁函数和清空函数的区别
{
if(!S.head)//需要单独的写出来,因为pankong函数的return并不能使得我们的本函数退出,这个是无奈之举,不可封装函数
{
cout<<"您还没有创建栈,所以怎么操作"<<endl;
return ;
}
if(S.top==S.head)
{
cout<<"此栈是空栈"<<endl;
}
int a=S.len;//因为后边S.len会发生变化,我们需要提前规避这个风险
for(int i=0;i<a;i++)
{
deletetop(S);//删除栈顶元素
}
free(S.head);//删除后head还是存在head这个指针的,只是我们先前开辟的空间被删除,所以我们输出head还是会有一个地址的
//我想了好多好多,我发现既然你要传入的是一个执行销毁的函数那么,你是不是实现传递过去了一个你已经创建的栈,
//当你进行一系列的操作后,你的指针由指向空变成了一个野指针(当然在不受你管理后)
S.head=NULL;
S.top=NULL;
S.len=0;
cout<<"销毁成功"<<endl; //请特别注意清空与销毁函数的区别
}
void outtop(stack S)//输出顶嘛
{
if(!S.head)//需要单独的写出来,因为pankong函数的return并不能使得我们的本函数退出,这个是无奈之举,不可封装函数
{
cout<<"您还没有创建栈,所以怎么操作"<<endl;
return ;
}
if(S.top==S.head)
{
cout<<"此栈是空栈"<<endl;
}
S.head->next=S.top;
cout<<"栈顶元素是"<<S.top->data<<endl;
}
void outstack(stack S)//输出栈的数据
{
if(!S.head)//需要单独的写出来,因为pankong函数的return并不能使得我们的本函数退出,这个是无奈之举,不可封装函数
{
cout<<"您还没有创建栈,所以怎么操作"<<endl;
return ;
}
if(S.top==S.head)
{
cout<<"此栈是空栈"<<endl;
}
cout<<"您创建的函数是:"<<endl;
S.head->next=S.top;
for(int i=0;i<S.len;i++)
{
cout<<S.top->data<<endl;
S.top=S.top->next;
}
}
void outlen(stack S)//输出长度
{
if(!S.head)//需要单独的写出来,因为pankong函数的return并不能使得我们的本函数退出,这个是无奈之举,不可封装函数
{
cout<<"您还没有创建栈,所以怎么操作"<<endl;
return ;
}
if(S.top==S.head)
{
cout<<"此栈是空栈"<<endl;
}
cout<<"此栈的长度是"<<S.len<<endl;
}
|