• 链式栈


         我们需要明确下边这个事实:我们写的函数都是对外的接口,也就是说,我们只需告诉别的程序员我们程序预留的接口(在这个程序里边是一些函数),别的程序员就可以使用我们的代码片段。不需要了解我们的栈是用什么类型的数据结构实现的。我们可以从我们写的代码中体会到这个事实。

         首先我们需要确定我们使用的数据结构,也就是我们链式栈的结构体StackNode,所以开始我们写出了下边的代码:    

       1: #include <stdio.h>
       2:  
       3: typedef struct StackNode
       4: {
       5:     int data;        // 数据域
       6:     StackNode *next; // 下一结点的指针域
       7: }StackNode, *Stack;
       8:  
       9: int main()
      10: {
      11:     return 0;
      12: }

          问题1:StackNode和Stack分别代表什么?

        

         OK,有了链式栈的数据结构,我们就开始写函数了。所有的程序都是因为有需求才存在的,所以我们需要设想一下链式栈的需求。可能某天有某个程序员需要使用栈了,这时候他就开始看说明文档了(假如这个说明文档是我们自己写的):

       1: // 链式栈的用法如下:
       2: int main()
       3: {
       4:     // 初始化一个链式栈(这个时候就有链式栈的头结点了,也就是说我们可以操作它了)
       5:     Stack stack = InitStack();
       6:     Push(stack, 3); // 3进栈
       7:     Push(stack, 4); // 4进栈
       8:     Push(stack, 5); // 5进栈
       9:  
      10:     printf("%d\n", Pop(stack));
      11:     printf("%d\n", Pop(stack));
      12:     printf("%d\n", Pop(stack));
      13:     printf("%d\n", Pop(stack)); // 第4次出栈,应该出错
      14:  
      15:     return 0;
      16: }

         OK,有了需求,我们可以根据需求来写代码了,首先我们看第5行,初始化栈,上边的注释写的是初始化一个头结点。OK,我们可以对应写出如下代码:

       1: // 初始化一个链式栈(返回一个链式栈的头结点)
       2: Stack InitStack()
       3: {
       4:     Stack stack = (Stack)malloc(sizeof(StackNode));
       5:     stack->next = NULL;
       6:     return stack;
       7: }

         问题2:头结点的作用是什么?

         初始化结束以后就可以做入栈和出栈的操作了,我们可以写出如下入栈和出栈的代码:

         入栈:

       1: void Push(Stack stack, int newData)
       2: {
       3:     // 判断是否为空,Just For Safty :-D
       4:     if(stack == NULL)
       5:     {
       6:         printf("栈未初始化,请初始化以后再使用\n");
       7:         return;
       8:     }
       9:  
      10:     // 找到最后一个节点
      11:     StackNode *lastNode = stack;
      12:     while(lastNode->next)
      13:     {
      14:         lastNode = lastNode->next;
      15:     }
      16:  
      17:     lastNode->next = (StackNode*)malloc(sizeof(StackNode));
      18:     lastNode->next->data =  newData;
      19:     lastNode->next->next = NULL;
      20:  
      21:     printf("入栈成功!\n");
      22: }

         问题3:请简述一下11行到19行的思想

         出栈:

       1: int Pop(Stack stack)
       2: {
       3:     // 判断栈是否为空
       4:     if(!stack->next)
       5:     {
       6:         printf("栈为空,无法出栈\n");
       7:         return -1; // -1只是一个自定义的错误码, 不必深究
       8:     }
       9:  
      10:     // 找到最后一个节点的前一个节点
      11:     // tempNode: 最后一个节点的前一个节点
      12:     StackNode *tempNode = stack;
      13:     // 问题4
      14:     while(tempNode->next->next)
      15:     {
      16:         tempNode = tempNode->next;
      17:     }
      18:     
      19:     // 问题5
      20:     int data = tempNode->next->data;
      21:     free(tempNode->next);
      22:     tempNode->next = NULL;
      23:     return data;
      24: }

         问题4:就该程序来说,Pop的返回值是由谁决定的?

         问题5:请自己实现函数:bool IsEmpty(Stack stack),要求:栈为空时返回true,栈非空时返回false

         下边是完整代码:

    /************************************************************************/
    /* 链式栈                                                               */
    /************************************************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    
    // StackNode: 链式栈的一个节点
    // Stack: 指向链式栈头结点的指针
    typedef struct StackNode
    {
    	int data;        // 数据域
    	StackNode *next; // 下一结点的指针域
    }StackNode, *Stack;
    
    // 初始化一个链式栈(返回一个链式栈的头结点)
    Stack InitStack()
    {
    	Stack stack = (Stack)malloc(sizeof(StackNode));
    	stack->next = NULL;
    	return stack;
    }
    
    void Push(Stack stack, int newData)
    {
    	// 判断是否为空,Just For Safty :-D
    	if(stack == NULL)
    	{
    		printf("栈未初始化,请初始化以后再使用\n");
    		return;
    	}
    
    	// 找到最后一个节点
    	StackNode *lastNode = stack;
    	while(lastNode->next)
    	{
    		lastNode = lastNode->next;
    	}
    
    	lastNode->next = (StackNode*)malloc(sizeof(StackNode));
    	lastNode->next->data =  newData;
    	lastNode->next->next = NULL;
    
    	printf("入栈成功!\n");
    }
    
    int Pop(Stack stack)
    {
    	// 判断栈是否为空
    	if(!stack->next)
    	{
    		printf("栈为空,无法出栈\n");
    		return -1; // -1只是一个自定义的错误码, 不必深究
    	}
    
    	// 找到最后一个节点的前一个节点
    	// tempNode: 最后一个节点的前一个节点
    	StackNode *tempNode = stack;
    	while(tempNode->next->next)
    	{
    		tempNode = tempNode->next;
    	}
    	
    	int data = tempNode->next->data;
    	free(tempNode->next);
    	tempNode->next = NULL;
    	return data;
    }
    
    // 链式栈的用法如下:
    int main()
    {
    	// 初始化一个链式栈(这个时候就有链式栈的头结点了,也就是说我们可以操作它了)
    	Stack stack = InitStack();
    	Push(stack, 3); // 3进栈
    	Push(stack, 4); // 4进栈
    	Push(stack, 5); // 5进栈
    
    	printf("%d\n", Pop(stack));
    	printf("%d\n", Pop(stack));
    	printf("%d\n", Pop(stack));
    	printf("%d\n", Pop(stack)); // 第4次出栈,应该出错
    
    	return 0;
    }
    
  • 相关阅读:
    c# DataTable获取某个列的集合
    DataTable中的select()用法(转)
    java中,数组toString()方法,数组常用操作
    C# 如何重写ToString函数及重写的意义,自定义类重写ToString()方法
    重写List 的ToString方法 -------C#
    设置响应报文头 image/jpeg
    response 设置响应头的常用几种方法
    [C#]Http请求报头设置
    HttpContext.Current.Session.Abandon() 大坑 要注意
    for循环拼接字符串去掉最后的逗号
  • 原文地址:https://www.cnblogs.com/xiaobo68688/p/2109823.html
Copyright © 2020-2023  润新知