单向链表实现堆栈

来源:互联网 发布:上海日料放题 知乎 编辑:程序博客网 时间:2024/06/05 20:38

单向链表实现堆栈

要求:

1 使用C语言;

2 使用单向链表;

3 接口规范,通用性强;

解:

1 链表元素的类型确定

为了最终确定这两个函数的调用模型,你还需要知道进出堆栈的数据是属于哪种类型的。也就是说,你得声明一个struct结构作为链表元素的数据类型。

如果没有特殊要求,应该考虑使用无类型指针来实现一个通用的解决方案。基于无类型指针的struct结构和函数调用模型如下所示:

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. typedef struct elementT  
  2. {  
  3.     struct elementT*next;  
  4.     void *data;  
  5. }element;  

2 push(压入)和pop(弹出)

push(压入)和pop(弹出)例程是每一种堆栈实现方案中都不可缺少的。

2.1 push例程设计过程

首先,把某堆栈作为一个输入参数传递给这个函数;

其次,把将被压入堆栈的某项数据传递给push函数。

要想把某个堆栈作为一个输入参数,最简单的办法莫过于在函数调用过程中传递一个指向该堆栈的指针。

因为堆栈将被实现为一个单向链表,所以这个指向堆栈的指针就将是一个指向该链表第一个元素的指针。

除这个指向堆栈的指针外,你还需要把那个将被压入堆栈的数据安排为push函数的第二个输入参数。

2.2 pop函数设计过程

pop函数看上去有一个指向某堆栈的指针作为其输入参数就已经足够了。但仔细想下,它还需要把从堆栈上弹出的数据值返回给它的调用者。

大致得到pop和push函数的原型如下:

void push(element *stack,void*data);  //标红的地方有错误,随后解释

void pop(element *stack,void **data);

 

注:在C语言里,你对传递给子函数作为其输入参数的某个指针所做出的修改时无法反映到其父函数里。要解决这一问题,你就必须把一个指针的指针传递给被调用例程作为参数。

为了对其父函数中的堆栈指针做出修改,必须把一个指向堆栈指针的指针传递给例程push和pop作为输入参数。只有这样,你才能保证父函数中的堆栈指针正确地指向链表的头元素。考虑了这一因素的Push和pop调用模型如下。

void Push(element **stack,void*data);

void Pop(element **stackvoid **data);

 

3 考虑出错处理

push里要为链表中的新元素动态地分配内存。内存分配是一项可能会失败的操作,所以在编写push例程的时候必须要检查这个内存分配操作是否成功。还需要把push操作是否成功通知给它的调用者。采用返回值表示push操作是否成功。

pop要注意,不能对一个空堆栈进行弹出操作。所以它应该设置一个错误代码,当对空堆栈操作时,返回错误代码,那么弹出的数据放哪儿呢?放在输出参数里。

4 创建与删除堆栈

创建堆栈和删除堆栈两个函数原型:

int CreateStack(element**stack); 

int DeleteStack(element**stack);

push函数为新元素分配内存,检查内存分配操作是否失败,对新元素进行赋值,把新元素放到堆栈的栈顶,最后对堆栈指针做出调整。如下所示: 

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. int push(element **stack, void *data)  
  2. {  
  3.     element *elem;  
  4.     elem = (element *)malloc(sizeof(element));  
  5.     if(!elem)  
  6.         renturn 0;  
  7.    
  8.     elem->data = data;  
  9.     elem->next = *stack;  
  10.     *stack = elem;  
  11.   
  12.     return 1;  
  13. }  

 

 pop函数先检查堆栈是否为空,然后取回栈顶元素中的数据值,对堆栈指针做出调整,在释放原堆栈元素所占用的内存。如下所示:

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. int pop(element **stack, void **data)  
  2. {  
  3.     element*elem;  
  4.     if(!(elem= *stack))  
  5.         return 0;  
  6.    
  7.     *data= elem->data;  
  8.     *stack= elem->next;  
  9.     free(elem);  
  10.    
  11.     return 1;  
  12. }  



// CreateStack函数将堆栈指针设为NULL,并返回一个表示操作成功的1

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. int CreateStack(element **stack)  
  2. {  
  3.     *stack = NULL;  
  4.     return 1;  
  5. }  

DeleteStack函数可以用反复调用pop函数的办法来实现,但一边遍历堆栈数据结构一边是否个链表元素的办法将更有效率。在释放当前元素的时候,你需要使用一个临时指针来保存指向下一个元素的指针。这一点千万不要忘了。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. int DeleteStack(element **stack)  
  2. {  
  3.     element *next;  
  4.     while(*stack)  
  5.     {  
  6.         next= (*stack)->next;  
  7.         free(*stack);  
  8.         *stack= next;  
  9.     }  
  10.   
  11.     return1;  
  12. }  


 

 参考《程序员面试攻略》
0 0
原创粉丝点击