C语言 复杂的栈(链表栈)
//复杂的栈--链表栈 #include<stdio.h> #include<stdlib.h> #define datatype int//定义链表栈数据类型 //定义链表栈结构 struct stacklink{ datatype data; struct stacklink *pnext; }; typedef struct stacklink StackLink; //判断栈是否为空 int isempty(StackLink *phead); //进栈 StackLink * push(StackLink *phead, datatype num); //出栈 StackLink * pop(StackLink *phead, StackLink *pout); //清空 StackLink * setempty(StackLink *phead); //遍历栈中的数据 void findall(StackLink *phead); //链表栈容量无限大,但是代价是增加链表遍历成本 void main(){ //定义链表栈的头指针 StackLink * phead = NULL; //压栈 phead = push(phead, 1); phead = push(phead, 2); phead = push(phead, 3); phead = push(phead, 4); phead = push(phead, 5); //打印栈中的数据 findall(phead); //出栈 StackLink *pout = (StackLink *)malloc(sizeof(StackLink)); phead = pop(phead, pout); printf("\n弹出的元素是%d;\n", pout->data); free(pout); ////全部出栈 //while (phead!=NULL){ // StackLink *pout = malloc(sizeof(StackLink)); // phead = pop(phead, pout); // printf("\n弹出的元素是%d;\n", pout->data); // free(pout); //} printf("\n================================\n"); //打印栈中的数据 findall(phead); printf("\n================================\n"); //清空栈内元素 phead = setempty(phead); //打印栈中的数据 findall(phead); system("pause"); } //判断栈是否为空 int isempty(StackLink *phead){ if (phead == NULL) { return 1; } else{ return 0; } } //进栈 StackLink * push(StackLink *phead, datatype num){ //分配内存空间 StackLink *p = (StackLink *)malloc(sizeof(StackLink)); StackLink *p1 = phead; p->data = num; p->pnext = NULL; //判断栈是否为空 if (isempty(phead)) { //栈为空 phead = p; //注意:这里是给指针副本phead赋值,但是main()函数里phead的值并没有变化 //要在函数里修改一个指针的值,应该使用二级指针,但是根据代码优化原则,尽量不使用二级指针, //因此我们将phead当做返回值返回 } else{ while (p1->pnext != NULL){ p1 = p1->pnext; } p1->pnext = p; //这里的phead->pnext会直接影响main()函数里phead的值,因为phead->pnext本质上等于(*phead).pnext //修改的是phead指针指向数据的值,而不是修改phead本身 } return phead; } //遍历栈中的数据 void findall(StackLink *phead){ StackLink *p = phead; while (p != NULL){ printf("%d\n", p->data); p = p->pnext; } } //出栈 StackLink * pop(StackLink *phead, StackLink *pout){ if (phead == NULL)//判断栈是否为空 { return NULL; } else{ pout->pnext = NULL; //不为空 //出栈,每次弹出最后一个 //分两种情况 //1.只有一个元素,只有一个元素,只需要弹出头指针本身 if (phead->pnext == NULL) { //pout = phead; 错误,这样只是改变pout指向的地址,而free(phead)会彻底释放phead指向地址的内存 //结果就是pout也为NULL pout->data = phead->data; //注意:链表栈删除必须释放内存 free(phead); phead = NULL; //这个改变形参phead的值,所以只能返回phead,而有任何地方修改pout的值 return phead; } //2.多个元素,找到倒数第二个元素 else{ StackLink *p = phead; while (phead->pnext->pnext != NULL){ phead = phead->pnext; } pout->data = phead->pnext->data; //删除栈中最后一个元素 free(phead->pnext); phead->pnext = NULL; return p; } } } //清空 StackLink * setempty(StackLink *phead){ //清空的思路是,1,2,3,4,5通过头指针找到1,将2删除,把3移到2的位置上,再删除3 //不太清楚循环次数,所以用while StackLink *p = NULL; while (phead->pnext != NULL){//当第二个元素是NULL的时候,退出循环 //删除第二个 //p是第三个的指针 p = phead->pnext->pnext; //开始删除第二个 free(phead->pnext); phead->pnext = p; } //最后删除第一个元素 free(phead); return NULL; }