Teach you how to write sequence table

Table of contents

1. What is the function of the sequence table?

2. Realize the various functions of the sequence table

1. Preparation

2. Initialize the sequence table

3. Sequence table expansion

4. Print sequence table

5. Add sequence table members

5.1 tail increase

5.2 head increase

 6. Delete the contents of the members in the sequence table

6.1 Tail deletion

6.2 Header deletion

 7. Find members

 8. Modify (replace)

9. Insert (insert a member at the target position)

10. Directed deletion (delete members at the target location)

3. All codes

1. Function header file

2. Function implementation


1. What is the function of the sequence table?

This is like an outline, as long as we clarify the functions to be realized, we will work hard to realize them. As we all know, the sequence table is to store the data we need in the form of an array in the computer memory. Now that the data has been saved, the next step is to perform corresponding operations on the saved data. It is necessary to add, delete, modify and check . Then, we want to print out the contents in the sequence table to see if they are correct. To store the data we need, we can design another printing function. If we want to sort the contents of the sequence table, we can also design a sorting function. Anyway, design according to our own needs, but adding, deleting, modifying and checking are the most basic and must have .

2. Realize the various functions of the sequence table

1. Preparation

Before realizing the various functions of the sequence table, we have to prepare some pre-preparation content, the member type of the sequence table, the design of the structure of the sequence table, the reference of the header file...The author recommends that these operations be placed in one header file, so that we only need to refer to a header file to complete the functions we need when calling.

// SeqList.h
//将所需函数和所需头文件的引用放在一个头文件中,那么在使用的时候就只用引用一个头文件
#pragma once//防止头文件被重复引用
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//可能要用到的头文件
typedef int SlDateType;
//将int typedef成SlDateType这样就可以区分int和顺序表成员
// 虽然它们的类型本质上都是int但是它们的字面含义已经不同
//当然了,可以把int换成别的类型
//这样子设计其实更多的是为了到时顺序表成员类型想更换直接从这换就全换了,不用一个一个换
typedef struct seqlist
{
	SlDateType* a;
	//创建一个指针类型的顺序表成员数据,为什么是指针?
	//这样做是为了到时能够使用malloc和realloc对空间的大小进行开辟与修改
	//相当于柔性数组
	int sz;//已经存放了多少个成员
	int capacity;//容量大小,以后判定空间是否够用可以通过这个来判定
}seqlist;//将结构体名字命名为seqlist,使用时更加方便

2. Initialize the sequence table

Remember to quote the previous sequence table header file before writing the code, so that the contents of the sequence table header file can be used.

//顺序表.c
#include"顺序表.h"
void init_seqlist(seqlist* s1)//通过指针的形式访问,便能够对内容进行修改
{
	s1->capacity = 3;//将容量大小初始化为3,为了更好地测试到时的扩容效果
	s1->sz = 0;//将成员数量初始化为0,代表着此时没有存放成员
	s1->a = (SlDateType*)malloc(sizeof(SlDateType) * s1->capacity);
	//将顺序表的成员数组大小初始化和容量一样的大小
	if (s1->a == NULL)//开辟失败的话直接退出程序
	{
		exit(-1);
	}
}

After writing the content of the function in the sequence table.c, don't forget to quote it in the sequence table.h, so that others can use the corresponding function only by citing a header file.

3. Sequence table expansion

One thing we should pay attention to before storing the members of the sequence table is that our capacity is limited, so when the capacity is touched, that is, when the sequence table is full, we should expand the capacity to avoid the content that cannot be loaded situation occurs.

void if_enough(seqlist* s1)
{
	if (s1->sz == s1->capacity)
	//当容量和成员个数相当时,显然就已经存满了,需要扩容
	{
		s1->a = realloc(s1->a,sizeof(SlDateType)*s1->capacity*2);
		//将容量扩大到原来容量的两倍
		if (s1->a == NULL)
		{
			perror("if_enough");//错误提示
			return;//中止程序
		}
		s1->capacity *= 2;//扩容成功,容量翻倍
		printf("扩容成功,当前容量为%d\n",s1->capacity);//扩容成功给个提示
	}
}

4. Print sequence table

Before adding, we will realize such a problem. If I add members of the sequence table, how can I tell that I have successfully added members of the sequence table? Does it sound confusing? In fact, we cannot directly see the contents of the sequence table, so we can use the printing method to print out the contents of the sequence table.

void print_seqlist(const seqlist* s1)
//将内容打印出来,但内容是不会被改变的,因此用const修饰,避免内容被修改
{
	if (s1->sz == 0)
	{
		printf("顺序表为空,操作失败\n");
		return;
	}
	int i = 0;
	for (i = 0; i < s1->sz; i++)
	{
		printf("%d ", s1->a[i]);//将内容通过循环的方式打印出来
	}
	printf("\n");//打印完所有内容之后最好换行
}

5. Add sequence table members

5.1 tail increase

What is a tail increase? As the name suggests, it starts to increase from the end, that is, add members at the end of the sequence table. Note: before adding, we need to judge whether the sequence table is full. At this time, we can use the if_enough function we created before to judge whether It needs to be expanded, and if it is needed, it will be expanded, and if it is not needed, nothing will happen.

void seqlist_pushback(seqlist*s1,SlDateType x)
{
	if_enough(s1);
	s1->a[s1->sz] = x;//在顺序表的最后插入一个数据x
	s1->sz++;
}

Create a new file and test the code we wrote earlier 

//test.c
#include"顺序表.h"
int main()
{
	seqlist s1;
	init_seqlist(&s1);//初始化顺序表
	print_seqlist(&s1);
	//将顺序表内容打印,但此时是空,故不能打印
	seqlist_pushback(&s1, 1);//依次将1,2,3放入顺序表中
	seqlist_pushback(&s1, 2);
	seqlist_pushback(&s1, 3);
	print_seqlist(&s1);//打印顺序表
	seqlist_pushback(&s1, 2);//依次将2,3放入顺序表中
	seqlist_pushback(&s1, 3);
	print_seqlist(&s1);//打印顺序表
}

5.2 head increase

As the name implies, members are added at the very beginning of the sequence table. It is not difficult to imagine, what if there are already members in this sequence table? Is it possible to directly replace this member with our target? If you do this, there will be one less member. According to the experience of the array, we can only move all the members back by one unit by overwriting, and then replace the front member with the member we need. Also before we start, we should judge whether the capacity is enough.

Moving is the core here, and it is also a science. The author draws a picture for everyone here, and everyone will know how to move.

 As can be seen from the figure, we need to move the last member back to the next space, that is, the content of the space corresponding to sz, which must be the content of the space of sz-1, and the content of sz-1 must be the content of sz-2 , then it can be realized in a circular way, the content pointed to by sz-i is equal to the content pointed to by sz-i-1, and i realizes the coverage step by step. The cycle ends when sz-i-1=0, why? , because when sz-i-1=0, sz-i is equal to 1, that is, the target corresponding to 1 is equal to the target corresponding to 0. After this step is completed, all coverage is over. According to the calculation, i= sz-1, so i<sz can achieve all coverage.

void seqlist_pushfront(seqlist* s1, SlDateType x)
{
	if_enough(s1);
	int i = 0;
	for (i=0;i<s1->sz;i++)//通过循环从后往前覆盖
	{
		s1->a[s1->sz - i] = s1->a[s1->sz-i-1];
	}
	s1->a[0] = x;//将首元素替换成x
	s1->sz++;
}

 You can also test it

//test.c
#include"顺序表.h"
int main()
{
	seqlist s1;
	init_seqlist(&s1);//初始化顺序表
	print_seqlist(&s1);
	//将顺序表内容打印,但此时是空,故不能打印
	seqlist_pushback(&s1, 1);//依次将1,2,3放入顺序表中
	seqlist_pushback(&s1, 2);
	seqlist_pushback(&s1, 3);
	print_seqlist(&s1);//打印顺序表
	seqlist_pushfront(&s1,520);//在最前面放入520
	print_seqlist(&s1);//打印顺序表
}

 6. Delete the contents of the members in the sequence table

6.1 Tail deletion

This is very simple, we only need to dial back the number of members in the sequence table by one. Why? For example, if there are already 1, 2, 3, 4, 5 in the members, it is not difficult to find that sz is 5 at this time, pointing to the space behind 5, and when we call back the number, sz points to 4. At this time, sz points to the space corresponding to 5, and this space will be automatically overwritten when you add content next time. Similarly, printing is also printed according to sz, and it will be skipped directly. The only thing to note is that when the members of the sequence table are empty, that is, when there are no members, forcibly deleting them will cause an out-of-bounds problem. Because when there are no members, sz is 0, and if you delete it forcibly, it will cause sz=-1, and the next time you add elements, you will access out of bounds.

void seqlist_popback(seqlist* s1)
{
	if (s1->sz == 0)
	{
		printf("顺序表为空,操作失败\n");
		return;
	}
	s1->sz--;
}

6.2 Header deletion

Head deletion is more troublesome than tail deletion. We overwrite the previous content with the latter content by overwriting from front to back

void seqlist_popfront(seqlist* s1)
{
	if (s1->sz == 0)
	{
		printf("顺序表为空,操作失败\n");
		return;
	}
	int i = 0;
	for (i = 1; i < s1->sz; i++)
	{
		s1->a[i-1] = s1->a[i];//从前往后覆盖
	}
	s1->sz--;
}

Similarly, we can test 

 7. Find members

The goal is very simple. It is to find the target member and print it out. If you can’t find it, you can print it out. It can be done through one traversal.

void seqlist_fine(const seqlist* s1,const SlDateType x)
//查找的目标是x,用const修饰是因为只是查找,不用修改
{
	if (s1->sz == 0)
	{
		printf("顺序表为空,操作失败\n");
		return;
	}
	int i = 0;
	for (i = 0;i<s1->sz; i++)
	{
		if (s1->a[i] == x)//相等意味着找到了
		{
			printf("找到%d了,下标为%d\n",x,i);
			return;
		}
	}
	printf("目标不存在\n");
}

You can also test it 

 8. Modify (replace)

Give the corresponding subscript and the modified result to modify the content of the target subscript. It should be noted that the scope of our modification of the subscript can only be modified in the member group. What does it mean? That is to say, we cannot modify the subscripts that have not yet placed members

void seqlist_modify(seqlist* s1, int pos, const SlDateType x)
{
	if (pos >= s1->sz)
	//当pos=sz时就已经是对还不是成员的空间进行操作了,更别说后面的了
	{
		printf("当前空间还不是成员的一部分,操作失败\n");
		return;
	}
	s1->a[pos] = x;
}

You can also test it

9. Insert (insert a member at the target position)

It should be noted that what is the range of our insertion, obviously 0~sz-1 can be inserted, there is already content in it, so can sz? Yes, because inserting at the position of sz is equivalent to tail insertion, and there is one more thing to note, that is, inserting members, the number of members will increase, so that is to say, we also need to judge whether expansion is needed before inserting.

void seqlist_insert(seqlist* s1, int pos, const SlDateType x)
{
	if_enough(s1);
	if (pos > s1->sz)//比sz还大,意味着插入的位置会导致连续性被破坏
	{
		printf("插入位置出错,操作失败\n");
		return;
	}
	int i = 0;
	for (i = 0;i<s1->sz-pos; i++)
	{
		s1->a[s1->sz-i] = s1->a[s1->sz-i-1];//从后向前覆盖
	}
	s1->a[pos] = x;
	s1->sz++;
}

have a test

10. Directed deletion (delete members at the target location)

With the previous experience of inserting, this is very simple, but one thing to note is that its deletion range can only be 0~sz-1, sz is not included, because sz is obviously not a member yet.

void seqlist_erase(seqlist* s1, int pos)
{
	if (pos >= s1->sz)//等于sz时就已经是在删除未被定义的内容了
	{
		printf("删除位置出错,操作失败\n");
		return;
	}
	int i = 0;
	for (i=0;pos+i+1<s1->sz;i++)
	{
		s1->a[pos+i] = s1->a[pos+i+1];//从前向后覆盖
	}
	s1->sz--;
}

have a test

 When we have completed the insertion and directional deletion, in fact, the previous head-plug deletion and tail-plug deletion can be replaced by these two functions, so we won’t show them one by one here, and the upgraded version is directly placed in all the codes.

3. All codes

1. Function header file

// SeqList.h
//将所需函数和所需头文件的引用放在一个头文件中,那么在使用的时候就只用引用一个头文件
#pragma once//防止头文件被重复引用
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//可能要用到的头文件
typedef int SlDateType;
//将int typedef成SlDateType这样就可以区分int和顺序表成员
// 虽然它们的类型本质上都是int但是它们的字面含义已经不同
//当然了,可以把int换成别的类型
//这样子设计其实更多的是为了到时顺序表成员类型想更换直接从这换就全换了,不用一个一个换
typedef struct seqlist
{
	SlDateType* a;
	//创建一个指针类型的顺序表成员数据,为什么是指针?
	//这样做是为了到时能够使用malloc和realloc对空间的大小进行开辟与修改
	//相当于柔性数组
	int sz;//已经存放了多少个成员
	int capacity;//容量大小,以后判定空间是否够用可以通过这个来判定
}seqlist;//将结构体名字命名为seqlist,使用时更加方便
//初始化顺序表
void init_seqlist(seqlist*s1);
//打印顺序表
void print_seqlist(const seqlist* s1);
//尾增
void seqlist_pushback(seqlist* s1, SlDateType x);
//头增
void seqlist_pushfront(seqlist* s1, SlDateType x);
//尾删
void seqlist_popback(seqlist* s1);
//头删
void seqlist_popfront(seqlist* s1);
//查找成员
void seqlist_fine(const seqlist* s1,const SlDateType x);
//修改成员
void seqlist_modify(seqlist* s1, int pos, const SlDateType x);
//插入成员
void seqlist_insert(seqlist* s1, int pos, const SlDateType x);
//删除成员
void seqlist_erase(seqlist* s1, int pos);

2. Function implementation

//顺序表.c
#include"顺序表.h"
void init_seqlist(seqlist* s1)//通过指针的形式访问,便能够对内容进行修改
{
	s1->capacity = 3;//将容量大小初始化为3,为了更好地测试到时的扩容效果
	s1->sz = 0;//将成员数量初始化为0,代表着此时没有存放成员
	s1->a = (SlDateType*)malloc(sizeof(SlDateType) * s1->capacity);
	//将顺序表的成员数组大小初始化和容量一样的大小
	if (s1->a == NULL)//开辟失败的话直接退出程序
	{
		exit(-1);
	}
}
void if_enough(seqlist* s1)
{
	if (s1->sz == s1->capacity)
	//当容量和成员个数相当时,显然就已经存满了,需要扩容
	{
		s1->a = realloc(s1->a,sizeof(SlDateType)*s1->capacity*2);
		//将容量扩大到原来容量的两倍
		if (s1->a == NULL)
		{
			perror("if_enough");//错误提示
			return;//中止程序
		}
		s1->capacity *= 2;//扩容成功,容量翻倍
		printf("扩容成功,当前容量为%d\n",s1->capacity);//扩容成功给个提示
	}
}
void print_seqlist(const seqlist* s1)
//将内容打印出来,但内容是不会被改变的,因此用const修饰,避免内容被修改
{
	if (s1->sz == 0)
	{
		printf("顺序表为空,操作失败\n");
		return;
	}
	int i = 0;
	for (i = 0; i < s1->sz; i++)
	{
		printf("%d ", s1->a[i]);//将内容通过循环的方式打印出来
	}
	printf("\n");//打印完所有内容之后最好换行
}
void seqlist_pushback(seqlist*s1,SlDateType x)
{
	//if_enough(s1);
	//s1->a[s1->sz] = x;//在顺序表的最后插入一个数据x
	//s1->sz++;
	seqlist_insert(s1,s1->sz,x);
}
void seqlist_pushfront(seqlist* s1, SlDateType x)
{
	//if_enough(s1);
	//int i = 0;
	//for (i=0;i<s1->sz;i++)//通过循环从后往前覆盖
	//{
	//	s1->a[s1->sz - i] = s1->a[s1->sz-i-1];
	//}
	//s1->a[0] = x;//将首元素替换成x
	//s1->sz++;
	seqlist_insert(s1,0, x);
}
void seqlist_popback(seqlist* s1)
{
	/*if (s1->sz == 0)
	{
		printf("顺序表为空,操作失败\n");
		return;
	}
	s1->sz--;*/
	seqlist_erase(s1,s1->sz-1);
}
void seqlist_popfront(seqlist* s1)
{
	//if (s1->sz == 0)
	//{
	//	printf("顺序表为空,操作失败\n");
	//	return;
	//}
	//int i = 0;
	//for (i = 1; i < s1->sz; i++)
	//{
	//	s1->a[i-1] = s1->a[i];//从前往后覆盖
	//}
	//s1->sz--;
	seqlist_erase(s1,0);
}
void seqlist_fine(const seqlist* s1,const SlDateType x)
//查找的目标是x,用const修饰是因为只是查找,不用修改
{
	if (s1->sz == 0)
	{
		printf("顺序表为空,操作失败\n");
		return;
	}
	int i = 0;
	for (i = 0;i<s1->sz; i++)
	{
		if (s1->a[i] == x)//相等意味着找到了
		{
			printf("找到%d了,下标为%d\n",x,i);
			return;
		}
	}
	printf("目标不存在\n");
}
void seqlist_modify(seqlist* s1, int pos, const SlDateType x)
{
	if (pos >= s1->sz)
	//当pos=sz时就已经是对还不是成员的空间进行操作了,更别说后面的了
	{
		printf("当前空间还不是成员的一部分,操作失败\n");
		return;
	}
	s1->a[pos] = x;
}
void seqlist_insert(seqlist* s1, int pos, const SlDateType x)
{
	if_enough(s1);
	if (pos > s1->sz)//比sz还大,意味着插入的位置会导致连续性被破坏
	{
		printf("插入位置出错,操作失败\n");
		return;
	}
	int i = 0;
	for (i = 0;i<s1->sz-pos; i++)
	{
		s1->a[s1->sz-i] = s1->a[s1->sz-i-1];//从后向前覆盖
	}
	s1->a[pos] = x;
	s1->sz++;
}
void seqlist_erase(seqlist* s1, int pos)
{
	if (pos >= s1->sz)//等于sz时就已经是在删除未被定义的内容了
	{
		printf("删除位置出错,操作失败\n");
		return;
	}
	int i = 0;
	for (i=0;pos+i+1<s1->sz;i++)
	{
		s1->a[pos+i] = s1->a[pos+i+1];//从前向后覆盖
	}
	s1->sz--;
}

Well, today’s sharing is over here, thank you friends for visiting, I wish you all a bright future O(∩_∩)O

Guess you like

Origin blog.csdn.net/fq157856469/article/details/131972550