1, Overview
Stack is sometimes used in daily development, such as reducing recursive functions to non recursive loops, or parsing xml tags. The c language standard library does not have a stack structure. Here is a stack implementation method, which is based on array implementation and supports dynamic capacity expansion.
2, Principle description
1. Array based stack
The simplest implementation of stack is based on array. Set a stack top subscript in an array to point to the stack top. When entering the stack, write elements at the top of the stack, and when leaving the stack, reduce the stack top subscript.
2. Dynamic compatibilization
In the dynamically resized array stack, the operation of out of the stack and into the stack is basically the same as that of the ordinary array stack. Only when the elements in the array are full, it will automatically increase the capacity, apply for a new and larger space, and copy the original data.
3, Programming
1. Interface design
(1) . data structure
Here, the structure is directly defined in the header file to facilitate users to freely select stack memory instantiation. The required fields are basically the same as ordinary stacks. The element size field is added to adapt to different data types. The specific codes are as follows:
#include<stdint.h> #include<stddef.h> /// <summary> ///Stack /// </summary> typedef struct { /// <summary> ///Element size /// </summary> size_t _elementSize; /// <summary> ///Number of elements /// </summary> size_t _count; /// <summary> ///Data array /// </summary> uint8_t* _data; /// <summary> ///Array capacity /// </summary> size_t _capacity; }acf_stack;
(2) . method
① Initialization
The stack needs to be initialized before use. The stack can be initialized by passing in the pointer of the stack object and the size of the stack element.
/// <summary> ///Initialization stack /// </summary> ///< param name = "_this" > pointer to stack object < / param > ///< param name = "_elementsize" > element size < / param > void acf_stack_init(acf_stack* _this, size_t elementSize);
② De initialization
After use, the stack needs to be de initialized to free up resources.
/// <summary> ///De initialization stack /// </summary> ///< param name = "_this" > pointer to stack object < / param > void acf_stack_deinit(acf_stack* _this);
③ Stack
Press the element into the tail, and the pointer of the element is passed in. When the number of elements is greater than the stack array, it will be automatically resized.
/// <summary> ///Stack /// </summary> ///< param name = "_this" > pointer to stack object < / param > ///< param name = "pelement" > pointer to element < / param > void acf_stack_push(acf_stack* _this, void* pElement);
④ Out of stack
The stack top element is out of the stack. If the stack is not empty and out of the stack, it returns success, otherwise it returns failure.
/// <summary> ///Out of stack /// </summary> ///< param name = "_this" > pointer to stack object < / param > ///< returns > 1 successfully exits the stack, 0 failed < / returns > int acf_stack_pop(acf_stack* _this);
⑤ Get stack top element
Only get the top element of the stack without leaving the stack. Returns a pointer to the top element of the stack.
/// <summary> ///Get stack top element /// </summary> ///< param name = "_this" > pointer to stack object < / param > ///< returns > pointer to the top element of the stack < / returns > AC_API void* acf_stack_peek(acf_stack* _this);
⑥ Get element
Gets the element according to the subscript. Returns a pointer to the top element of the stack.
/// <summary> ///Get element /// </summary> ///< param name = "_this" > pointer to stack object < / param > ///Subscript of < param name = "index" > element < / param > ///< returns > pointer to the top element of the stack < / returns > void* acf_stack_get_element(acf_stack* _this, size_t index);
⑦ Get stack length
Gets the number of elements in the stack.
/// <summary> ///Get stack length /// </summary> ///< param name = "_this" > pointer to stack object < / param > ///< returns > stack length < / returns > size_t acf_stack_get_count(acf_stack* _this);
⑧ Get stack capacity
Gets the length of the current stack array.
/// <summary> ///Get stack capacity /// </summary> /// <param name="_this"></param> ///< returns > stack capacity < / returns > size_t acf_stack_get_capacity(acf_stack* _this);
⑨ Empty stack
Clear all elements in the stack.
/// <summary> ///Empty stack /// </summary> ///< param name = "_this" > pointer to stack object < / param > void acf_stack_clear(acf_stack* _this);
⑩ Volume contraction
Shrink the stack array length to the number of elements.
/// <summary> ///Volume contraction ///The stack will only increase and increase capacity according to elements, and will not decrease capacity according to elements. This method is called if it is necessary to reduce capacity. /// </summary> ///< param name = "_this" > pointer to stack object < / param > void acf_stack_trim_excess(acf_stack* _this);
2. Key implementation
(1) . dynamic capacity increase
When the elements in the stack are larger than the length of the array, you need to increase the length of the array.
static int acf_stack_set_capacity(acf_stack* _this, size_t newCapacity) { if (newCapacity < _this->_count) return 0; if (newCapacity == _this->_capacity) return 1; if (newCapacity) { uint8_t* newData = realloc(_this->_data, newCapacity * _this->_elementSize); if (!newData) return 0; _this->_data = newData; } else { if (_this->_data) { free(_this->_data); _this->_data = NULL; } } _this->_capacity = newCapacity; return 1; }
(2) , stack
Before entering the stack, you need to judge whether the element is full. If it is full, you need to increase the capacity. The capacity increase method is twice the capacity increase. The specific implementation is as follows:
void acf_stack_push(acf_stack* _this, void* pData) { if (_this->_count == _this->_capacity) { if (_this->_capacity < 4) acf_stack_set_capacity(_this, 4); else acf_stack_set_capacity(_this, _this->_capacity *2); } memcpy(_this->_data + _this->_count * _this->_elementSize, pData, _this->_elementSize); _this->_count++; }
(3) . capacity shrinkage
When the stack array capacity is too large, you can manually call the capacity shrinkage method to reduce unnecessary space waste. Referring to c# the stack, the specific implementation is as follows:
void acf_stack_trim_excess(acf_stack* _this) { size_t threshold = (size_t)(((double)_this->_capacity) * 0.9); if (_this->_count < threshold) { acf_stack_set_capacity(_this, _this->_count); } }
3. Use examples
(1) , integer element
main.c
#include "Collection/acf_stack.h" #include<stdio.h> int main() { acf_stack stack1; //initialization acf_stack_init(&stack1, sizeof(int)); //Push for (int i = 0; i < 50; i++) { acf_stack_push(&stack1, &i); } //Get the number of elements printf("count:%d\n", acf_stack_get_count(&stack1)); //Get array capacity printf("capacity:%d\n", acf_stack_get_capacity(&stack1)); //Volume contraction acf_stack_trim_excess(&stack1); //Get array capacity printf("trim capacity:%d\n", acf_stack_get_capacity(&stack1)); printf("pop:"); //Out of stack do { int* pI = acf_stack_peek(&stack1); if (pI) printf("%d ", *pI); } while (acf_stack_pop(&stack1)); printf("\n"); //Push for (int i = 0; i < 50; i++) { acf_stack_push(&stack1, &i); } //Traversal stack printf("traverse:"); for (int i = 0; i < 50; i++) { int* pI = acf_stack_get_element(&stack1, i); if (pI) printf("%d ", *pI); } printf("\n"); //Clear element acf_stack_clear(&stack1); printf("clear count:%d\n", acf_stack_get_count(&stack1)); //De initialization acf_stack_deinit(&stack1); return 0; }
(2) , structural element
#include "Collection/acf_stack.h" #include<stdio.h> typedef struct { int i; int j; }A; int main() { acf_stack stack2; //initialization acf_stack_init(&stack2, sizeof(A)); //Push for (int i = 0; i < 50; i++) { A a; a.i = i; a.j = i; acf_stack_push(&stack2, &a); } //Get the number of elements printf("count:%d\n", acf_stack_get_count(&stack2)); //Get array capacity printf("capacity:%d\n", acf_stack_get_capacity(&stack2)); //Volume contraction acf_stack_trim_excess(&stack2); //Get array capacity printf("trim capacity:%d\n", acf_stack_get_capacity(&stack2)); printf("pop:"); //Out of stack do { A* pA = acf_stack_peek(&stack2); if (pA) printf("%d ", pA->i); } while (acf_stack_pop(&stack2)); printf("\n"); //Push for (int i = 0; i < 50; i++) { A a; a.i = i; a.j = i; acf_stack_push(&stack2, &a); } //Traversal stack printf("traverse:"); for (int i = 0; i < 50; i++) { A* pA = acf_stack_get_element(&stack2, i); if (pA) printf("%d ", pA->j); } printf("\n"); //Clear element acf_stack_clear(&stack2); printf("clear count:%d\n", acf_stack_get_count(&stack2)); //De initialization acf_stack_deinit(&stack2); return 0; }
(3) , pointer element
#include "Collection/acf_queue.h" #include<stdio.h> #include<stdlib.h> typedef struct { int i; int j; }A; int main() { acf_stack stack3; //initialization acf_stack_init(&stack3, sizeof(A*)); //Push for (int i = 0; i < 50; i++) { A* a = malloc(sizeof(A)); a->i = i; a->j = i; acf_stack_push(&stack3, &a); } //Get the number of elements printf("count:%d\n", acf_stack_get_count(&stack3)); //Get array capacity printf("capacity:%d\n", acf_stack_get_capacity(&stack3)); //Volume contraction acf_stack_trim_excess(&stack3); //Get array capacity printf("trim capacity:%d\n", acf_stack_get_capacity(&stack3)); printf("pop:"); //Out of stack do { A** pA = acf_stack_peek(&stack3); if (pA) { printf("%d ", (*pA)->i); //Free resources to prevent memory leaks free(*pA); } } while (acf_stack_pop(&stack3)); printf("\n"); //Push for (int i = 0; i < 50; i++) { A* a = malloc(sizeof(A)); a->i = i; a->j = i; acf_stack_push(&stack3, &a); } //Traversal stack printf("traverse:"); for (int i = 0; i < 50; i++) { A** pA = acf_stack_get_element(&stack3, i); if (pA) { printf("%d ", (*pA)->j); //Free resources to prevent memory leaks free(*pA); } } printf("\n"); //Clear element acf_stack_clear(&stack3); printf("clear count:%d\n", acf_stack_get_count(&stack3)); //De initialization acf_stack_deinit(&stack3); return 0; }
4. Complete code