Lucky to be appreciated by the rich, how can the sequence table not be
Sequence table
Linear table
A linear list is a finite sequence of n data elements with the same characteristics. Linear table is a data structure widely used in practice. Common linear tables: sequential table, linked list, stack, queue, string
A linear table is logically a linear structure, that is, a continuous straight line. However, the physical structure is not necessarily continuous. When the linear table is stored physically, it is usually stored in the form of array and chain structure.
But today's blog only talks about the sequence table
Sequential table (essentially array)
Concept and structure
Sequential table is a linear structure in which data elements are stored in sequence with a storage unit with continuous physical addresses. Generally, array storage is used. Complete the addition, deletion, query and modification of data on the array.
The sequence table can generally be divided into:
1. Static sequence table: use fixed length array to store elements.
#pragma once //It is convenient to change the size of the array #define N 100 typedef int SLDataType; //This will be easy to modify //Static sequence table typedef struct SeqList { SLDataType a[N]; SLDataType size;//Indicates how many data are stored in the array }SL; void SeqListPushBack(SL* ps, SLDataType x);
The static feature is not to allow insertion when it is full. The disadvantage is that we don't know how much space is appropriate, waste when it is large and "crime" when it is small, so there is a dynamic sequence table
2. Dynamic sequence table: use dynamic array storage.
Since they are all dynamic, there is no need for the space size N. We can use the pointer
//It is convenient to change the size of the array //#define N 100 typedef int SLDataType; //This will be easy to modify //Dynamic sequence table typedef struct SeqList { SLDataType* a; int size;//Indicates how many data are stored in the array int capacity;//How much space can the array actually hold data }SL; void SeqListPushBack(SL* ps, SLDataType x);
Interface function (here I teach you to close the pit, otherwise sometimes you don't know how to die (the difference between value transfer and address transfer))
Sequence table initialization SeqListInit
pass by value
A caveat here is that vs13 is different from vs19. vs13 can run without initialization, while vs19sl can't run without initialization. I'll put the figure below
Address transfer
Since the of the argument cannot be passed to the formal parameter, we will pass the address
//Sequence table initialization void SeqListInit(SL* ps) { ps->a = NULL; ps->size = ps->capacity = 0; }
Tail interpolation function SeqListPushBack
//Tail insertion void SeqListPushBack(SL* ps, SLDataType x) { if (ps->size == ps->capacity) { //There's no room at all //Capacity expansion when the space is full int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType)); if (tmp == NULL) { printf("Development failure\n");//Failed to open up successfully exit(-1);//Abnormal end } //After successful capacity expansion ps->a = tmp;//Give him the new address ps->capacity = newcapacity;//Give him the capacity } //Enough space ps->a[ps->size] = x; ps->size++; }
But sometimes it's a waste of time to debug to see how our interface is written, so we have to write a print function
Sequence table printing function SeqListPrint
//Sequence table printing void seqListPrint(SL* ps) { int i = 0; for (i = 0; i < ps->size; i++) { printf("%d ", ps->a[i]); } printf("\n"); }
We can basically see this step as a successful start of the sequence table. Now we need to destroy the sequence table. In fact, we know that the last is the destruction of the sequence table, but we can realize it here (you can understand it as the smallest system of single chip microcomputer or the version of micro star)
Sequence table destruction function seqlistdestroy
//Sequence table destruction void seqListDestory(SL* ps)//Is to free memory and prevent memory overflow { free(ps->a); ps->a = NULL; ps->capacity = ps->size = 0; }
When the minimum system board is ready, we will add modules one by one
Tail deletion function SeqListPopBack
tender
//Tail deletion void SeqListPopBack(SL* ps) { //Gentle approach if (ps->size > 0) { ps->size--; } }
Rough (I, a big man, prefer to be rough and straightforward)
//Tail deletion void SeqListPopBack(SL* ps) { Gentle approach //if (ps->size > 0) //{ // ps->size--; //} //Rough assert(ps->size > 0);//It doesn't matter if you assert that it's not true and report an error directly ps->size--; }
Before writing the header insert, let's think about it. If you want to insert, you must consider whether you need to expand the capacity. Then it is heavier than the expansion in the previous tail insert, so you can extract it and write a function separately
Sequence table check capacity function SeqListCheckCapacity
//Sequence table check capacity void SeqListCheckCapacity(SL* ps) { if (ps->size == ps->capacity) { //There's no room at all //Capacity expansion when the space is full int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType)); if (tmp == NULL) { printf("Development failure\n");//Failed to open up successfully exit(-1);//Abnormal end } //After successful capacity expansion ps->a = tmp;//Give him the new address ps->capacity = newcapacity;//Give him the capacity } }
Then you can easily expand the capacity by checking the capacity with that
Header insertion function SeqListPushFront
//Head insert void SeqListPushFront(SL* ps, SLDataType x) { //Check capacity increase SeqListCheckCapacity(ps); //Mobile data int end = ps->size - 1; while (end>=0) { ps->a[end + 1] = ps->a[end]; end--; } ps->a[0] = x; ps->size++; }
Header delete SeqListPopFront
//Header deletion void SeqListPopFront(SL* ps) { assert(ps->size>0); int begin = 1; while (begin<ps->size) { ps->a[begin-1] = ps->a[begin]; begin++; } ps->size--; }
Sequence table lookup function SeqListFind
//Sequential table lookup function int SeqListFind(SL* ps, SLDataType x) { int i = 0; for (i = 0; i < ps->size; i++) { if (ps->a[i] == x) return i; } return -1; }
Sequential table insert function SeqListInsert
//Sequential table insert function void SeqListInsert(SL* ps, int pos, SLDataType x) { //Assertion does not end directly in scope assert(pos>=0 && pos<=ps->size); //Check expansion SeqListCheckCapacity(ps); //Mobile data int end = ps->size - 1; while (pos<=end) { ps->a[end + 1] = ps->a[end]; end--; } //Then give the data to the current location ps->a[pos] = x; ps->size++; }
Therefore, there is no need to write the head insert and tail insert. You can call the insert function directly
Sequence table delete function SeqListErase
//Sequential table deletion function void SeqListErase(SL* ps, int pos) { //Assertion does not end directly in scope assert(pos >= 0 && pos < ps->size); //When deleting, you do not need to consider capacity expansion, but directly move the data int begin = pos; while (begin+1<ps->size) { ps->a[begin] = ps->a[begin + 1]; begin++; } ps->size--; }
Therefore, header deletion and tail deletion can be reused
Exercises
Example 1 Removing Elements
Let's analyze the problem first. He has requirements for space complexity and no requirements for time complexity
int removeElement(int* nums, int numsSize, int val){ int i = 0; int* cur = nums; for(i = 0;i<numsSize;i++) { if(val ^ nums[i]) { *cur++ = nums[i]; } } return cur-nums; }
Example 2 Remove duplicates from an ordered array
We can't look at it empty. We have to draw a picture to solve it. The problem directly determines the space. It won't give you an additional array, so we can only solve it with multiple pointers
Brain simulation, a positioning pointer, two cursor pointers, should be able to solve
int removeDuplicates(int* nums, int numsSize){ if(numsSize == 0)//Empty array jump out return 0; int* cur = nums;//Positioning pointer int* head = nums;//Swim header pointer int* tail = nums+1;//Cursor tail pointer while(tail<nums+numsSize) { if(*head == *tail) { tail++; } else { *cur = *head; cur++; head = tail; tail++; } } *cur = *head;//The last one is forced to be assigned regardless of equality cur++; return (cur-nums); }
Example 3 Merge two ordered arrays
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){ int* p1 = nums1+m-1; int* p2 = nums2+n-1; int* cur = nums1+m+n-1; while(p1>=nums1 && p2>=nums2) { *cur-- = *p1>*p2 ? *p1-- : *p2--;//ternary operator } while(p2>=nums2) { *cur-- = *p2--; } }