您的位置:首页 > 编程语言 > C语言/C++

(C语言版)栈和队列(一)——实现链式栈和链式队列的基本操作以及遇到的问题

2014-02-27 16:49 751 查看
首先要感谢这位大牛的一篇博客,地址如下:http://blog.csdn.net/hguisu/article/details/7674195

当然还有网上一些其他的资料,今天自己写了一下链式栈和链式队列的程序。其中在释放内存的时候遇到了些许问题,通过调,找出了原因,在这里我与大家分享一下。

(1)链式栈的相关代码块

Stack.h 头文件——定义了节点结构和链式栈结构,以及基本操作函数的声明部分

#ifndef _STACK_H_H
#define _STACK_H_H

typedef struct Node
{
int data;
struct Node *pNext;
}NODE, *pNODE;

typedef struct Stack
{
pNODE top;
}STACK, *pSTACK;

//栈初始化
void InitStack(pSTACK stack);

//入栈
void PushStack(pSTACK stack, int data);

//出栈
void PopStack(pSTACK stack, int *data);

//判断栈是否为空
int IsEmptyStack(pSTACK stack);

//获得栈顶元素
int GetTopStack(pSTACK stack);

//释放内存
void FreeMemory(pSTACK stack);

#endif


Stack.cpp 源文件——定义链式栈的基本操作函数的定义
说明:一开始对栈初始化,但是这个栈是没有头节点的,直接定义了一个指针(top)刚开始指向NULL。

入栈的时候就是让top指针始终指向栈顶元素,入栈的节点的指针指向top指针,这样不断的进行入栈操作,节点不断增加,但是top指针一直是指针最后插入的节点。

出栈的时候就是从top指针指向的节点还是释放,然后让top指针指向被释放节点的下一个节点,这样节点不断释放,top指针不断向下移动。

所以,栈就成了一个“先进后出”的结构。

#include "Stack.h"
#include <stdlib.h>
#include <stdio.h>

//栈初始化
void InitStack(pSTACK stack)
{
stack->top = NULL;
}

//入栈
void PushStack(pSTACK stack, int data)
{
pNODE p_new = (pNODE)malloc(sizeof(NODE));

if (NULL == p_new)
{
printf("内存分配失败!\n");
exit(EXIT_FAILURE);
}

p_new->data = data;
p_new->pNext = stack->top; //这里要注意
stack->top = p_new;
}

//出栈
void PopStack(pSTACK stack, int *data)
{
pNODE p_delete = stack->top;

if (IsEmptyStack(stack))
exit(EXIT_FAILURE);

*data = p_delete->data;
stack->top = p_delete->pNext;
free(p_delete);
p_delete = NULL;
}

//判断栈是否为空
int IsEmptyStack(pSTACK stack)
{
if (stack->top == NULL)
return 1;
else
return 0;
}

//获得栈顶元素
int GetTopStack(pSTACK stack)
{
int data;
if (stack->top == NULL)
exit(EXIT_FAILURE);

data = stack->top->data;
return data;
}

//释放内存
void FreeMemory(pSTACK stack)
{
pNODE p_delete = NULL;

while (stack->top != NULL)
{
p_delete = stack->top;
stack->top = p_delete->pNext;
free(p_delete);
p_delete = NULL;
}
}


main.cpp  测试程序——通过简单的交互界面测试函数的功能

#include <stdio.h>
#include "Stack.h"

int main(void)
{
int number, i, data, flag;
STACK s;
InitStack(&s);

printf("请输入入栈个数:");
scanf("%d", &number);
for (i=1; i<number+1; i++)
{
printf("请输入第%d个栈点元素值:", i);
scanf("%d", &data);
PushStack(&s, data);
}

PopStack(&s ,&data);
printf("出栈的元素值为:%d\n", data);

data = GetTopStack(&s);
printf("当前栈顶元素值为:%d\n", data);

FreeMemory(&s);
flag = IsEmptyStack(&s);
if (flag)
printf("内存释放成功!\n");
else
printf("内存释放失败!\n");

return 0;
}


(2)链式队列的相关代码

Queue.h 头文件——定义了节点结构和队列结构,以及链式队列的基本操作函数的声明

#ifndef _QUEUE_H_H
#define _QUEUE_H_H

typedef struct Node
{
int data;
struct Node *pNext;
}NODE, *pNODE;

typedef struct Queue
{
pNODE front;
pNODE rear;
}QUEUE, *pQUEUE;

//初始化队列
void InitQueue(pQUEUE queue);

//入队列
void EnQueue(pQUEUE queue, int data);

//出队列
void DeQueue(pQUEUE queue, int *data);

//判断队列是否为空
int IsEmptyQueue(pQUEUE queue);

//获得队头元素值
int GetFrontQueue(pQUEUE queue);

//释放内存
void FreeMemory(pQUEUE queue);

#endif


Queue.cpp 源文件——定义了基本操作函数的定义

说明:一开始对链式队列进行初始化,这里就创建了一个节点(但是记得后面释放内存的时候这里也要释放),创建了这个节点是为了方便后面的操作,这样一开始队列的头指针和尾指针都指向了这个节点,但是此时的队列是空的,就像循环链表里头节点不参与运行是一样的道理。

入队列的时候就是进入的节点排在初始化时创建的节点后面,然后尾指针指针指着新进入的节点,但是头指针不动,节点不断进入队列,尾指针不断向后移动,保持尾指针一直指着刚进入的节点。

出队列的时候就是让头指针指向的节点的指针指向要释放节点的下一个节点,节点不断出队列,这里头指针实质上并没有移动,但是它指向的节点的指针一直在变化,一直保持者指向要释放节点的下一个节点,但是这里要注意,就是当队列中只剩下一个节点的时候(这里不包含初始化创建的那个节点),释放了这个节点以后尾指针成了野指针,那么这个时候就要让尾指针和头指针指向同一位置,那么这样判断队列是否为空的时候就是空了。

//链式队列代码
#include <stdlib.h>
#include <stdio.h>
#include "Queue.h"

//初始化队列
void InitQueue(pQUEUE queue)
{
queue->front = (pNODE)malloc(sizeof(NODE));
queue->front->data = 0;
queue->front->pNext = NULL;

if (NULL == queue->front)
{
printf("内存分配失败!\n");
exit(EXIT_FAILURE);
}

queue->rear = queue->front;
}

//入队列
void EnQueue(pQUEUE queue, int data)
{
pNODE p_new = (pNODE)malloc(sizeof(QUEUE));

if (NULL == p_new)
{
printf("内存分配失败!\n");
exit(EXIT_FAILURE);
}

p_new->data = data;
p_new->pNext = NULL;
queue->rear->pNext = p_new;
queue->rear = p_new;
}

//出队列
void DeQueue(pQUEUE queue, int *data)
{
if (IsEmptyQueue(queue))
exit(EXIT_FAILURE);
pNODE p_delete = queue->front->pNext;
*data = p_delete->data;
queue->front->pNext = p_delete->pNext;
if (p_delete->pNext == NULL)
queue->rear = queue->front;
free(p_delete);
p_delete = NULL;
}

//判断队列是否为空
int IsEmptyQueue(pQUEUE queue)
{
if (queue->front == queue->rear)
return 1;
else
return 0;
}

//获得队头元素值
int GetFrontQueue(pQUEUE queue)
{
int data;
if (IsEmptyQueue(queue))
exit(EXIT_FAILURE);
data = queue->front->data;
return data;
}

//释放内存
void FreeMemory(pQUEUE queue)
{
pNODE p_delete = NULL;
while (queue->front != NULL)
{
p_delete = queue->front;
queue->front = p_delete->pNext;
if (p_delete->pNext == NULL)	//如果到达最后一个节点时,队尾指针为NULL
queue->rear = NULL;
free(p_delete);
p_delete = NULL;
}
}


main.cpp 测试程序——简单的交互界面测试函数功能

#include <stdio.h>
#include "Queue.h"

int main(void)
{
int number, i, data, flag;
QUEUE q;
InitQueue(&q);

flag = IsEmptyQueue(&q);
if (flag)
printf("初始化成功!\n");

printf("请输入入队列个数:");
scanf("%d", &number);
for (i=1; i<number+1; i++)
{
printf("请输入第%d个队点元素值:", i);
scanf("%d", &data);
EnQueue(&q, data);
}

DeQueue(&q ,&data);
printf("出队列的元素值为:%d\n", data);

data = GetFrontQueue(&q);
printf("当前栈顶元素值为:%d\n", data);

FreeMemory(&q);
if (q.front == NULL && q.rear == NULL)
printf("内存释放成功!\n");
else
printf("内存释放失败!\n");

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息