链式栈

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

     首先我们需要确定我们使用的数据结构,也就是我们链式栈的结构体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;
}
posted @ 2011-07-18 18:10  LiLiNiuNiu  阅读(617)  评论(4编辑  收藏  举报