Sequential storage definition
Speaking of so many linear tables, let's take a look at the first of the two physical structures of linear tables - sequential storage structure.
The sequential storage structure of linear table refers to the sequential storage of data elements of linear table with a section of storage units with continuous addresses. The sequential storage diagram of linear table (a1,a2,..., an) is as follows:
Sequential storage mode
The sequential storage structure of a linear table, to put it bluntly, is to find a block of space in the memory, occupy a certain memory space in the form of space occupation, and then store the data elements of the same data type in this space in turn. Since the types of each data element of a linear table are the same, you can use C language (the same for other languages) That is, the first data element is stored in the position where the index of the array is 0, and then the adjacent elements of the linear table are stored in the adjacent positions in the array.
In the linear table, we estimate the maximum storage capacity of the linear table and create an array. The length of the array is the maximum storage capacity. However, in actual use, we do not use the maximum storage capacity every time. We hope to use the space more efficiently. Therefore, we use malloc to apply for space and realloc to adjust the space size A little. You can see it Space allocation and release To understand the function in detail.
Look at the structure code of the sequential storage of the linear table.
#define INITSIZE 20 / / initial size #define EXPANDTIMES 2 / / expansion times of each time typedef int ELemType; //Use int to simulate data item type typedef struct { ElemType* data; //Initial location where data is stored int capacity; //Capacity (total: unused + used) int size;//Already used }Sqlist;
I won't talk more about arrays and pointers here. If you want to know, you can see my Arrays and pointers.
Init_List(*L)
bool Init_List(Sqlist *L) { assert(L != NULL);//Check the input. The use of null pointers may lead to the collapse of the program. Search for the specific reasons and do not explain them later L->data = (int*)malloc(sizeof(ELemType) * INITSIZE);//Request a heap space to store elements //Assert (L - > data! = null); / / because malloc may fail, judge if (L->data == NULL) { return false; } else { L->capacity = INITSIZE;//The initial capacity is set by macro definition L->size = 0;//Of course, the initial size is 0 return true; } }
In order to have dynamic space size, we use heap space as storage space here. Don't remember free
Change_List(*L, flag)
bool Change_List(Sqlist* L,int flag)//Change capacity { assert(L != NULL); ELemType* temp = L->data; int newsize = flag == -1 ? L->capacity / EXPANDTIMES : L->capacity * EXPANDTIMES;//Simple judgment, temp = (ELemType*)realloc(temp,newsize * sizeof(ELemType));//Capacity expansion may also fail to prevent old data loss if (temp == NULL) { return false; } else { L->data = temp;//Give the requested space to data L->capacity = newsize;//Change capacity return true; } }
Is_Empty(*L)
bool Is_Empty(Sqlist* L) { assert(L != NULL); return L->size == 0;//Just check that the size used is not 0, and it's ok }
Clear_List(*L)
bool Clear_List(Sqlist* L) { assert(L != NULL); free(L->data);//Because the space comes from malloc, free it if you don't need it Init_List(L);//The simplest way is to re initialize it, which eliminates the data and reduces the capacity //L->size = 0; / / the most simple way is that the data is valid, we has the final say, the capacity is unchanged. return true; }
GetElem_List(*L,i)
ELemType GetElem_List(Sqlist* L, int i) { assert(L != NULL && i < L->size && i >= 0);//Ensure that the changed subscript must be a valid subscript and will not be explained later return L->data[i]; }
LocateElem_List(*L,e)
int LocateElem_List(Sqlist* L, ELemType e) { assert(L != NULL); int pos = -1; for (int i = 0; i < L->size; i++)//Traversal is required { if (e == L->data[i]) { pos = i; break; } } return pos; }
Insert_List(*L,i,e)
bool Insert_List(Sqlist* L,int i,ELemType e) { assert(L != NULL && i >= 0 && i <= L->size);//In order to meet the definition of linear table, the subscript shall be tested if (L->capacity == L->size)//Capacity expansion is required due to insufficient capacity { if (!Change_List(L,1)) //Data can only be released after the expansion is successful { return false; } } int pos = L->size; while (L->size != i)//Move one bit back { L->data[pos] = L->data[pos - 1]; pos--; } L->data[pos] = e; L->size++; return true; }
For tail insertion, I = L - > size; for head insertion, i=0;
Delect_List(*L, i)
Reverse operation with insertion
bool Delect_List(Sqlist* L, int i)// { assert(L != NULL && i < L->size && i >= 0); while (i != L->size-1)//Move one bit forward { L->data[i] = L->data[i+1]; i++; } L->size--; if (L->capacity > INITSIZE && L->size < L->capacity / EXPANDTIMES) Change_List(L, -1); return true; }
Length_List(*L)
int Length_List(Sqlist* L) { assert(L != NULL); return L->size;//We have special data items to record the length. Just return it directly }
Destory_List(*L)
Because clear only clears the data (some of the storage space cannot be cleared), we need to free it
bool Destroy_List(Sqlist* L) { L->capacity = 0; L->size = 0; free(L->data);//Destroy can't use it at all, because 0 times any number is still 0 L->data = NULL; return true; }
Advantages and disadvantages of linear table sequential storage structure
advantage
There is no need to add additional storage space to represent the logical relationship between elements in the table.
It can quickly access the elements at any position in the table. (sequential reading is fast, O(1));
shortcoming
Insert and delete operations need to move a large number of elements O(n)
When the length of the linear table changes greatly, it is difficult to determine the capacity of the storage space (this is the case with arrays, so we have capacity expansion / reduction)
Causing "fragmentation" of storage space (capacity > size most of the time, some of the space is idle)