The imperial tycoon with a value of more than 100 million said to the small farmer, has the sequence table been met

Keywords: data structure linked list

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--;
    }
}

Posted by azul85 on Fri, 15 Oct 2021 16:18:52 -0700