[Data structure] You are already an adult, come and write the sequence table

It's time to make up stories again. It's time to tell stories. It's still that rookie college student. Under the beating of advanced mathematics and C language, I finally survived the first half of my freshman year. He is proficient in the instrument of beating back and forth, and he knows that if he does not continue to learn. It is very likely that his ideal of being a programmer will die prematurely, and then, the order list.

Linear table

What is a linear table?

A linear list is a finite sequence of n data elements with the same characteristics.

What are the common linear tables?
Sequence lists, linked lists, stacks, queues, strings... They will be mentioned in later articles. Today we mainly talk about sequence lists.

Note: A linear table is logically a linear structure, that is, a continuous straight line. However, the physical structure is not necessarily continuous. When a linear table is physically stored, it is usually stored in the form of an array and a chain structure.

sequence table

The sequence table is a linear structure in which data elements are sequentially stored in a segment of storage units with consecutive physical addresses , generally using array storage. Complete data addition, deletion, search and modification on the array.
It's probably like this:

simply put, it's a high-profile array.

Target

  • a dynamic sequence table
  • Implement basic interface functions such as additions, deletions, and changes

start!

A little bit of preparation

Ontology of the sequence table (dynamic version)

typedef int SLDataName;

typedef struct SeqList
{
    
    
	SLDataName* arr;  //指向动态开辟的数组
	size_t size;      //有效数据个数
	size_t capacity;  //容量
}SeqList;

initialization

int main()
{
    
    
	SeqList s;
	SeqListInit(&s);
}
  • Initialization can prevent the values ​​in the sequence table from being strange random values, which is convenient for later use.
  • The reason for taking the address here:
    1. We generally recommend address transfer. If the structure is very large, one copy will push a stack, and everyone will not want to live. ◇ヘ(;´Д`ヘ) Commemorating the picture sauce that was clipped here.
    2. Second, we all know that the formal parameters in the function are just a copy, and changes to the formal parameters do not affect the actual parameters.
//顺序表初始化
void SeqListInit(SeqList* psl)
{
    
    
	psl->arr = (SeqList*)calloc(1, sizeof(SLDataName));
	psl->capacity = 1;
	psl->size = 0; 
}

The capacity here can also be written as 0, but I did not write it in this way for the convenience of the next expansion.

destroy

//顺序表销毁
void SeqListDestory(SeqList* psl)
{
    
    
	free(psl->arr);
	psl->arr = NULL;
	psl->capacity = 0;
	psl->size = 0;
}

If it is not destroyed, there will be a memory leak problem. (Although the program ends the operating system will automatically recycle for you, but we can't develop this bad habit)

When free, the compiler will check whether the pointer is out of bounds. The errors reported at this time are generally out of bounds issues.

The destroy function is easy to write, and it's done after all is cleared.

Print

//顺序表打印
void SeqListPrint(SeqList* psl)
{
    
    
	for (int i = 0; i < psl->size; i++)
	{
    
    
		printf("%d ", psl->arr[i]);
	}
	printf("\n");
}

Just traverse, easy and happy.

Amplification function

//检查空间,如果满了,进行增容

void CheckCapacity(SeqList* psl)
{
    
    
    assert(psl); //断言防止指针为空
	
	if (psl->size == psl->capacity)
	{
    
    
		SLDataName* tmp =(SLDataName*) realloc(psl->arr,sizeof(SLDataName*) *(psl->capacity) * 2);
		if (tmp != NULL)
		{
    
    
			psl->arr = tmp;
			(psl->capacity) *= 2;
			printf("Success!\n");
		}
		else
		{
    
    
			printf("Opps!\n");  //扩容失败
			exit(-1)  //结束程序
		}
	}
}

If the effective data is equal to the capacity, we can consider increasing the capacity.
Here is the choice to expand to twice the original size. Of course, you can expand as much as you want. The data structure is still very loose in this regard.

  • When using realloc, pay attention to receiving with a tmp array first to prevent data loss due to expansion failure. (For details, you can go to msdn to find out how to use the realloc function)
  • If the expansion fails and the tmp pointer is NULL, the program ends.

interface function

tail plug

//顺序表尾插
void SeqListPushback(SeqList* psl, SLDataName x)
{
    
    
	assert(psl);
	
	CheckCapacity(psl);
	psl->arr[psl->size] = x;
	psl->size++;
}

Tail insertion is still very simple, it arr[psl->size]is exactly the position where we need to insert the number, and finally remember to add one to the number of valid data.

head plug

//顺序表头插
void SeqListPushhead(SeqList* psl, SLDataName x)
{
    
    
	assert(psl);
	
	CheckCapacity(psl);
	for (int i = psl->size; i > 0; i--)
	{
    
    
		psl->arr[i] = psl->arr[i - 1];
	}
	psl->size += 1;
	psl->arr[0] = x;
}

As long as the data is moved back one place in turn, and finally the data is inserted in the first place, the header insertion of the data is completed.

tail deletion

//顺序表尾删
void SeqListPopback(SeqList* psl)
{
    
    
	assert(psl);
	
	if (psl->size == 0)
	{
    
    
		printf("顺序表为空\n");
		return;
	}
	psl->size --;
}

Valid data reduction is deletion.
What, you said you didn't delete it, can you see it? If you can't see it, just delete it.

Anyway, when the data is added, there is no evidence to cover it.
Note that the sequence table is empty.

header deletion

//顺序表头删
void SeqListPophead(SeqList* psl)
{
    
    
	assert(psl);
	
	if (psl->size == 0)
	{
    
    
		printf("顺序表为空\n");
		return;
	}
    for (int i = 0; i <psl->size-1; i++)
	{
    
    
		psl->arr[i] = psl->arr[i + 1];
	}
	psl->size --;
}


The operation of reversing the idea of ​​​​head insertion plus tail deletion minus valid data is the head deletion of this stitching monster.
Still note that the sequence table cannot be empty.

Add and delete functions at the specified location

Find the specified location

//顺序表查找
int SeqListFind(SeqList* psl, SLDataName x)
{
    
    
	for (int i = 0; i < psl->size; i++)
	{
    
    
		if (psl->arr[i] == x)
			return i;
	}
	return -1;
}

Traverse, if found, return the subscript, if not found, return -1.
Simple and rude, very popular.

Insert data at the specified location

//顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataName x)
{
    
    
	// 暴力检查
	assert(psl);

	// 温和检查
	if (pos > psl->size)
	{
    
    
		printf("pos 越界:%d\n", pos);
		return;
	}

	CheckCapacity(psl);
	for (int i = psl->size; i > pos; i--)
	{
    
    
		psl->arr[i] = psl->arr[i - 1];
	}
	psl->size ++;
	psl->arr[pos] = x;
}

It is the promotion version of the head insertion method, so I won't go into details.

There is another way of writing: (i >= (int)pos)loop operation writing psl->arr[i+1] = psl->arr[i ];
Note: Since the type of pos is size_t, pay attention to the potential problem of shaping promotion.

Delete data at specified location

//顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos)
{
    
    
	assert(psl);
	assert(pos < psl->size);
	
	if (psl->size == 0)
	{
    
    
		printf("顺序表为空\n");
    	return;
    }
	for(int i = pos; i < psl->size-1; i++)
	{
    
    
		psl->arr[i] = psl->arr[i + 1];
	}
	psl->size--;
}

Just cover.

New notation for head and tail functions

With the addition and deletion functions at specified positions, we can use it for special cases.

  • Tail insertion is to insert data at the size position
  • Tail deletion is to delete data at the size-1 position
  • Header is inserting data at position 0
  • Header deletion is to delete data at position 0

It can save a lot of time, and writing the sequence list quickly is not a dream.

void SeqListPushBack(SeqList* psl, SLDataName x)
{
    
    
	assert(psl);
	
	SeqListInsert(psl, psl->size, x);
}

void SeqListPopBack(SeqList* psl)
{
    
    
	assert(psl);

	SeqListErase(psl, psl->size-1);
}

void SeqListPushFront(SeqList* psl, SLDataType x)
{
    
    
	assert(psl);

	SeqListInsert(psl, 0, x);
}

void SeqListPopFront(SeqList* psl)
{
    
    

	assert(psl);

	SeqListErase(psl, 0);
}

finally

  • The time complexity of accessing an element directly from a sequential table is O(1)
  • The time complexity of head insertion, head deletion or insertion at a specified position is O(n)

More drawings and these basically come out. (Caiji college students say so)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324109628&siteId=291194637