Chained storage of stack --- 2021.9.3

Previous link:

Sequential storage of stack - 2021.9.3

Chained storage of stack:

What is stack chained storage? We explained the sequential storage of stack in the previous lecture. Naturally, we can design the chain storage of stack next.

Then let's discuss it together!!!

In order to make everyone understand better, a picture is specially drawn for everyone to see:

Now let's think about a question: is the chain header node the top or bottom of the stack?
Under normal circumstances, the chain header node is used as the top of the stack. The reason is that when it is used as the top of the stack, due to the principle of first in and then out of the stack, it only needs to insert the header when entering the stack and delete the header when leaving the stack. At this time, it is not necessary to maintain the tail node of the chain list.

Next, start to analyze the code:

/***************************************************************/
//Chain storage of stack

struct LinkNode
{
	struct LinkNode *next;
}

struct LStack
{
	struct LinkNode pHeader;
	int m_Size;

}

typedef void * LinkStack;

//Initialization stack
LinkStack init_LinkStack()
{
	struct LStack * myStack = malloc(sizeof(struct LStack));

	if(myStack == NULL)
	{
		return NULL;
	}

	myStack->pHeader.next = NULL;
	myStack->m_Size = 0;

	return myStack;
}

#define MAX 1024
//Push 
void push_LinkStack(LinkStack stack,void * data)
{
	//Essential head insertion
	if(stack == NULL)
	{
		return;
	}
	if(data == NULL)
	{
		return;
	}

	struct LinkStack* myStack = stack;
	//Determine whether the stack is full
	if(myStack->m_Size == MAX)
	{
		return;
	}

	//Take out the first 4 bytes of the user
	struct LinkNode *myNode = data;

	myNode->next = myStack->pHeader.next;
	myStack->pHeader.next = myNode;

	myStack->m_Size++;

}


//Out of stack
void pop_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return;
	}	
	struct LinkStack* myStack = stack;

	if(myStack->m_Size == 0)
	{
		return;
	}

	//Essential header deletion
	//Creates a pointer to the first node
	struct LinkNode * pFirst = myStack->pHeader.next;
	myStack->pHeader.next = pFirst->next;

	myStack->m_Size--;

}
//Return to top of stack
void * top_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return NULL;
	}	
	struct LinkStack* myStack = stack;
	
	if(myStack->m_Size == 0)
	{
		return NULL;
	}

	return myStack->pHeader.next;

}
//Returns the size of the stack
int size_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return -1;
	}	
	struct LinkStack* myStack = stack;	

	return myStack->m_Size;

}
//Determine whether the stack is empty
int isEmpty_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return -1;
	}	
	struct LinkStack* myStack = stack;	
	if(myStack->m_Size == 0)
	{
		return 1;
	}	

	return 0;
}
//Destroy stack
void destroy_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return;
	}	
	
	free(stack);
	stack = NULL;


}
struct LinkNode
{
	struct LinkNode *next;
}

struct LStack
{
	struct LinkNode pHeader;
	int m_Size;

}

typedef void * LinkStack;

First, in the linked list, we only need to maintain the pointer field of each node. And initialize the head node of the linked list and the node size of the linked list in the linked list.

At the same time, as in the previous talks, you need to redefine the tail void * type for the access of the linked list to prevent users from directly configuring the member variables of the structure.

LinkStack init_LinkStack()
{
	struct LStack * myStack = malloc(sizeof(struct LStack));

	if(myStack == NULL)
	{
		return NULL;
	}

	myStack->pHeader.next = NULL;
	myStack->m_Size = 0;

	return myStack;
}

We need to apply for a space in the heap to store the linked list, and create a pointer variable to point to this space.

Similarly, for the sake of the preciseness of the algorithm, we need to judge whether the applied memory is valid. If it is valid, the program will continue to run. If it is invalid, the function will exit in advance.

Next, initialize the linked list, set the next node of the head node to be empty, set the node size in the linked list to 0, and finally return the pointer variable that has been successfully initialized for subsequent access.

void push_LinkStack(LinkStack stack,void * data)
{
	//Essential head insertion
	if(stack == NULL)
	{
		return;
	}
	if(data == NULL)
	{
		return;
	}

	struct LinkStack* myStack = stack;
	//Determine whether the stack is full
	if(myStack->m_Size == MAX)
	{
		return;
	}

	//Take out the first 4 bytes of the user
	struct LinkNode *myNode = data;

	myNode->next = myStack->pHeader.next;
	myStack->pHeader.next = myNode;

	myStack->m_Size++;

}

Similarly, for the sake of the rigor of the algorithm, we need to judge whether the entry parameters are valid. If they are valid, the program will continue to run. If they are invalid, the function will exit in advance. At the same time, as in the previous talks, you need to redefine the tail void * type for the access of the linked list to prevent users from directly configuring the member variables of the structure.

Since this function is a stack function, you need to first judge whether the number of linked lists in the stack is full. If it is full, exit the function directly.

Stacking is similar to header insertion, so we need to create a pointer variable to point to the node to be inserted, point the node pointer field to be inserted to the next pointer field of the header node, and point the next pointer field of the header node to the node pointer field to be inserted.

Finally, because it is the insertion of nodes, the node size of the linked list is accumulated, and so on.

void pop_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return;
	}	
	struct LinkStack* myStack = stack;

	if(myStack->m_Size == 0)
	{
		return;
	}

	//Essential header deletion
	//Creates a pointer to the first node
	struct LinkNode * pFirst = myStack->pHeader.next;
	myStack->pHeader.next = pFirst->next;

	myStack->m_Size--;

}

Similarly, for the sake of the rigor of the algorithm, we need to judge whether the entry parameters are valid. If they are valid, the program will continue to run. If they are invalid, the function will exit in advance. At the same time, as in the previous talks, you need to redefine the tail void * type for the access of the linked list to prevent users from directly configuring the member variables of the structure.

Since this function is an out of stack function, you need to first judge whether the number of linked lists in the stack is empty. If it is empty, exit the function directly.

Stack out is equivalent to header deletion, so we need to create a pointer variable to point to the first node of the linked list, and point the pointer field of the next of the header node to the pointer field of the next of the first node of the linked list.

Finally, because the node is deleted, the node size of the linked list is reduced, and so on.

void * top_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return NULL;
	}	
	struct LinkStack* myStack = stack;
	
	if(myStack->m_Size == 0)
	{
		return NULL;
	}

	return myStack->pHeader.next;

}

You only need to return the next node of the head node of the linked list. I won't repeat it here.

int size_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return -1;
	}	
	struct LinkStack* myStack = stack;	

	return myStack->m_Size;

}

You only need to return the node size of the linked list, which will not be repeated here.

int isEmpty_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return -1;
	}	
	struct LinkStack* myStack = stack;	
	if(myStack->m_Size == 0)
	{
		return 1;
	}	

	return 0;
}

If the node size of the linked list is 0, it means that the stack is empty and returns 1. If not, it returns 0.

void destroy_LinkStack(LinkStack stack)
{
	if(stack == NULL)
	{
		return;
	}	
	
	free(stack);
	stack = NULL;
}

You only need to free the memory space of the linked list through the free function, which will not be repeated here.

Conclusion

If you think this article is good, remember to praise and support!!!

Tags: data structure

Posted on Sat, 04 Sep 2021 00:44:14 -0400 by shamil