2.3 Data structure and algorithm-stack

introduction

I mentioned the term stack when talking about memory allocation in the C language. There are two types of memory: static memory and dynamic memory.

Among them, static memory is allocated in the stack, dynamic memory is allocated in the heap

An example of an irregular code:

#include <stdio.h>
#include <malloc.h>

void f(int k)
{
	int m;
	double * q = (double *)malloc(200);
}

int main(void)
{
	int i = 10;
	int * p = (int *)malloc(100);

	return 0;
}

In the above code, m, q, i, and p are static memory (local variables), which are allocated on the stack; malloc(100) and malloc(200) are dynamic memory, which are allocated on the heap

The static memory allocated in the stack is automatically allocated by the operating system, while the dynamic memory allocated in the heap is made by the programmer himself

The stack and heap here represent the way of allocating memory, static memory is memory allocated by pushing and popping the stack, and dynamic variables are memory allocated by heap sorting

Definition of stack

A stack is a storage structure that can realize a "first in, last out" data

A stack is similar to a box where things are put in, the things that are put in first are taken out last

Classification of stacks

Static stack: use array as the basic kernel

Dynamic stack: The basic kernel is linked list, which is the most used [in fact, some functions of linked list mentioned above have been cut off]

Stack algorithm

Pop from the stack: pop()

Push the stack: push() 

In fact, from the point of view of the algorithm, this stack is much simpler than the linked list, and there is no messy operation such as search, but the stack can accomplish a lot of things, let us wait and see

Intuitive performance of the stack

Algorithm code implementation of the stack [Pull + Push]

/*这个栈的构造过程中总共有两个结构体,注意它们的区分*/

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>


// 定义节点这个结构体的数据类型
typedef struct Node
{
	int data;
	struct Node * pNext;
}NODE, * PNODE;  //NODE和PNODE数据类型,分别代表struct Node和struct Node *


// 栈本身是通过这个结构体来实现的,类似于链表的头指针(无数据)和尾指针
typedef struct Stack
{
	PNODE pTop;     //指向栈的顶部,相当于尾指针,操作最频繁的位置,不需要首指针
	PNODE pBottom;  //指向栈的底部,相当于头指针
}STACK, * PSTACK;


//函数声明时不一定要写形参,但是需要写形参的数据类型
void init(PSTACK);
void push(PSTACK, int);
void traverse(PSTACK);
bool pop(PSTACK, int *);
bool empty(PSTACK);    //判断栈是否为空
void clear(PSTACK pS);



int main(void)
{
	int val;
	STACK S;  // 等价于 struct Stack S,里面的pTop和pBottom都有了,但是里面放的都是垃圾值,所以还没有形成栈

	init(&S);

	push(&S, -6);
	push(&S, 21);
	push(&S, 34);
	push(&S, -7);
	push(&S, 99);

	if (pop(&S, &val))
		printf("出栈的元素为 %d\n", val);
	
	traverse(&S);

	clear(&S);

	traverse(&S);

	return 0;
}


//初始化,造出一个空栈(pTop和pBottom指向一个不放数据的头结点)这才算构造成功
void init(PSTACK pS)   //传入地址
{
	//下面这两句话等价
	pS->pTop = new NODE;                        //C++方式,新建一个NODE并把地址赋给前面的
	//pS->pTop = (PNODE)malloc(sizeof(NODE));   //C语言方式
	
	if (NULL == pS->pTop)
	{
		printf("动态内存分配失败!\n");
		exit(-1);     //整个程序终止
	}
	else
	{
		pS->pBottom = pS->pTop;
		pS->pBottom->pNext = NULL;   //链表的头结点指针域置空,这一步千万不要忘,否则就不是链表了
	} 
}


//压栈
void push(PSTACK pS, int val)
{
	//第一步:先造一个节点出来
	PNODE pNew = (PNODE)malloc(sizeof(NODE));
	//第二步:新节点的数据域赋值,新节点的指针域指向下面节点(其实就是尚未改变的pTop),注意栈是从上往下指
	pNew->data = val;
	pNew->pNext = pS->pTop;
	//第三步:pTop上移指向新节点
	pS->pTop = pNew;
	return;
}


//遍历输出这个栈
void traverse(PSTACK pS)
{
	PNODE p;
	p = pS->pTop;
	printf("链表自顶向下依次为:\n");
	while (p != pS->pBottom)
	{
		printf("%d\n", p->data);
		p = p->pNext;
	}
	return;
}


//弹出栈内的最后一个元素,并把出栈的元素存入pVal指针所指向的变量中,出栈失败返回false
bool pop(PSTACK pS, int * pVal)
{
	if (empty(pS))
		return false;
	else
	{
		/* 下面这样写其实不好,内存泄漏
		*pVal = pS->pTop->data;
		pS->pTop = pS->pTop->pNext;
		return true;
		*/
		//应该这样写
		PNODE r = pS->pTop;
		*pVal = r->data;
		pS->pTop = r->pNext;
		free(r);
		r = NULL;
		return true;
	}
}

//判断栈是否为空
bool empty(PSTACK pS)
{
	if (pS->pTop == pS->pBottom)
		return true;
	else
		return false;
}


//清空数据,回到初始化状态,但是注意内存泄漏问题,所以不能直接pTop赋值为pBottom
void clear(PSTACK pS)
{
	if (empty(pS))
		return;
	else
	{
		PNODE p = pS->pTop;  //p在上面
		PNODE q = NULL;      //q在p下面,最开始可以是NULL
		
		//这个while循环很重要,可能要背下来了
		while (p != pS->pBottom)
		{
			q = p->pNext;
			free(p);
			p = q;
		}

		pS->pTop = pS->pBottom;
	}
}

The application of the stack [stack is very, very useful]

Function call (program flow) by pushing and popping the stack

Interrupt

Write a calculator: expression evaluation (a stack for arithmetic symbols, and a stack for values)

Memory allocation

Buffering

Walk the maze (store every selected intersection)

Guess you like

Origin blog.csdn.net/weixin_43450646/article/details/106936431