Explain the sequence table function in detail

foreword

With the continuous in-depth study of C language, we have to start to learn a little data structure to increase our internal strength. Although many high-level language sequence tables, linked lists, etc. can not be implemented by ourselves, we need to do it ourselves in C language. Realized, this does not mean that C language and other languages ​​​​are more different than C language. Let's simulate and implement this data structure through C language, which can give us a deeper understanding of some of the content we often use in other languages. Of course, what we have to learn is not only their implementation, but more importantly their ideas.


1. Sequence table

The sequential table is a linear table stored in the form of an array in the computer memory. The sequential storage of the linear table refers to storing each element in the linear table in sequence with a group of storage units with continuous addresses, so that the linear table is adjacent in logical structure . The data elements are stored in adjacent physical storage units . The sequence table is to store the nodes in the table in sequence in a group of storage units with continuous addresses in the computer memory.
The storage in memory is as follows:
insert image description here

Second, the function of the sequence table

The functions of common sequence tables include adding, deleting, searching, and modifying. There are some other functions: sorting, merging, returning the number of elements, etc.
Increase : Increase can be divided into head increase, tail increase and specified position increase, and specified position increase can be divided into increase on the left or right of the specified element.
Deletion : Deletion can be divided into head deletion, tail deletion and specified position deletion.
Find : As the name suggests, find the specified element or location.
Modify : Modify the specified element or the element at the position to other elements.
Sort : Sort the data in the structure.
Merge : Merge multiple structures into one.
Return the number of elements : display the specific number of elements in the sequence table.

Third, the realization of the sequence table

The implementation of the sequence table can be divided into static and dynamic .
The size of the static sequence table has been fixed, but the size of the dynamic sequence table can be changed. The use of the static sequence table is too limited, and there will be an embarrassing situation of wasted space and insufficient space. The dynamic sequence table solves the problem of the static sequence table. But we still have to learn about the static sequence table and observe the similarities and differences between dynamic and static. Our function implementations are all carried out by reference, and the need to pass values ​​is to avoid large-scale copying, which will cause waste of time and space.

1. Static implementation of sequence table

Creation of sequence table

#define MAX 10 //存放元素的最大个数
typedef int datatype;//把类型重新命名,方便后面的参数类型的修改,增加代码的鲁棒性
typedef struct SList//定义顺序表的结构体
{
    
    
	int position;//表中元素的个数和位置
	datatype arr[MAX];//用来存放元素
}SL;//把结构体类型重新命名为SL

What we have implemented is a simple sequence table, the storage type is int type data, and it is placed in an array of int type.

Initialization, printing and destruction of sequence table

void Initialization(SL *sl)//初始话顺序表
{
    
    
	assert(sl);//进行断言,防止传入的指针或者地址不合法而造成的错误
	sl->position = 0;//开始没有元素,所以位置为0
}
SL* InitializationList()
{
    
    
	SL* sl = (SL*)malloc(sizeof(SL));
	sl->position = 0;
	return sl;
}
void print(const SL *sl)//打印顺序表
{
    
    
	assert(sl);//进行断言
	for (int i = 0; i < sl->position; i++)
	{
    
    
		printf("%d ", sl->arr[i]);
	}
	printf("\n");
}
void Destroy1(SL* sl)//销毁顺序表
{
    
    
	assert(sl);
	sl->position = 0;//把元素个数置为0
}
void Destroy2(SL* sl)//销毁顺序表
{
    
    
	assert(sl);
	free(sl);//把空间进行释放
	sl->position = 0;
	sl = NULL;//把指针置空
}

There are two types of initialization of the sequence table, one is created in the main function and initialized through the first function, and the other is created in the function and returned to the main function through the return type. The destruction function is also designed for the above two initialization functions. The first one is not dynamically opened, so free cannot be used. The second one is the space dynamically opened in the function, so it needs to be released by free. prevent memory leaks.
Don't we have a static implementation here? Why do you still use dynamic development?
The static here means that the storage size of the data is constant. The memory required by a structure we dynamically develop is fixed. The size of the array in the structure is fixed. The number of its storage elements is the same as that of our structure. It is irrelevant whether the body is dynamically opened or not. related to the size of the array.
We are calling by reference. When we don't need to modify the element, we can add const to modify it to prevent us from modifying it.

Sequence table addition and deletion

Let's first look at the implementation of the code:

void Popback(SL* sl, datatype n)//头插
{
    
    
	assert(sl);//进行断言
	if (sl->position < MAX )//判断数组中是否还有空间
	{
    
    
		int sum = sl->position;//创建一个变量等于数组中插入元素后的位置
		for (; sum > 0; sum--)
		{
    
    
			sl->arr[sum] = sl->arr[sum - 1];//把插入元素后的前一个元素向后移动
		}
		sl->arr[sum] = n;//把数组中的一个元素设置为传入的值
		sl->position++;//元素位置向后移动
	}
	else
	{
    
    
		printf("空间不足\n");
		return;
	}
}
void Popfornt(SL* sl)//头删
{
    
    
	assert(sl);//进行断言
	int sum = 1;
	for (; sum < sl->position; sum++)
	{
    
    
		sl->arr[sum - 1] = sl->arr[sum];//把数组中元素进行前移进行覆盖
	}
	sl->position--; //元素位置向前移动
}
void Pushback(SL* sl, datatype n)//尾插
{
    
    
	assert(sl);
	if (sl->position < MAX)//判断数组中是否还有空间
	{
    
    
		sl->arr[sl->position] = n;//直接在数组后插入元素
		sl->position++;//元素位置向后移动
	}
	else
	{
    
    
		printf("空间不足\n");
		return;
	}
}
void Pushfornt(SL* sl)//尾删
{
    
    
	assert(sl);
	sl->position--;//直接进行个数减一,表明这个位置可以进行覆盖
}

Head insertion and head deletion : Insert the element at the first position of the array, so all elements behind the first position need to be moved backwards, and head deletion needs to overwrite all elements behind the first position forward.
End insertion and end deletion : directly insert the element at the last position or directly reduce the number of elements by one to achieve the effect of end insertion and end deletion.

void test1()//进行头删,尾删,头插,尾插。
{
    
    
	SL sl;
	Initialization(&sl);//初始话顺序表
	Popback(&sl, 1);//进行头插
	Popback(&sl, 2);
	Popback(&sl, 3);
	Popback(&sl, 4);
	Popback(&sl, 5);
	printf("头插后:");
	print(&sl);
	Pushback(&sl, 6);//进行尾插
	Pushback(&sl, 7);
	Pushback(&sl, 8);
	Pushback(&sl, 9);
	Pushback(&sl, 10);
	Pushback(&sl, 11);//超过数组中的大小,空间不足
	printf("尾插后:");
	print(&sl);//打印顺序表的元素
	Pushfornt(&sl);//进行尾删
	printf("尾删后:");
	print(&sl);
	Popfornt(&sl);//进行头删
	printf("头删后:");
	print(&sl);
	Destroy1(&sl);
}
int main()
{
    
    
	test1();
	return 0;
}

insert image description here

Insertion, query and modification of sequence table

The insertion and modification of the sequence table depend on the query function, so we need to implement the query of the sequence table first, and we can also directly modify the subscript elements we want to modify, but we generally don’t know what the subscript elements we want to modify are , so the search function is needed, such as the address book to be implemented, we can find the subscript of the person through the name, and then modify our value.
Here is our implementation code:

int Seeklift(const SL *sl, datatype n)//左查找
{
    
    
	assert(sl);
	int sum = 0;
	for (sum = 0; sum < sl->position; sum++)
	{
    
    
		if (sl->arr[sum] == n)//判断改下标的元素是否和我们所需的元素相同。
		{
    
    
			return sum+1;//数组下标从0开始,所以返回位置进行加1
		}
	}
	return -1;
}
int Seekright(const SL *sl, datatype n)//右查找
{
    
    
	assert(sl);
	int sum = sl->position-1;
	for (; sum >0; sum--)
	{
    
    
		if (sl->arr[sum] == n)
		{
    
    
			return sum+1;
		}
	}
	return -1;
}
void Modify(SL *sl, int n, datatype num)//修改
{
    
    
	assert(sl);
	sl->arr[n - 1] = num;//把坐标还原为数组的下标
}
void Insertpos(SL* sl, int n, datatype num)//按数组位置插入,在元素左插入
{
    
    
	assert(sl);
	//判断数组中是否还有空间
	if (sl->position < MAX)
	{
    
    
		int sum = sl->position;//创建一个变量等于数组中插入元素后的位置
		for (; sum > n-1; sum--)//把坐标还原为数组的下标
		{
    
    
			sl->arr[sum] = sl->arr[sum - 1];//把插入元素后的前一个元素向后移动
		}
		sl->arr[n-1] = num;//把数组中的一个元素设置为传入的值
		sl->position++;//元素位置向后移动
	}
	else
	{
    
    
		printf("空间不足\n");
		return;
	}
}
void Insertright(SL* sl, int n, datatype num)//在元素右插入
{
    
    
	assert(sl);
	//判断数组中是否还有空间
	if (sl->position < MAX)
	{
    
    
		int sum = sl->position;//创建一个变量等于数组中插入元素后的位置
		for (; sum > n; sum--)//把坐标还原为数组的下标
		{
    
    
			sl->arr[sum] = sl->arr[sum - 1];//把插入元素后的前一个元素向后移动
		}
		sl->arr[n] = num;//把数组中的一个元素设置为传入的值
		sl->position++;//元素位置向后移动
	}
	else
	{
    
    
		printf("空间不足\n");
		return;
	}
}

Search : We divide the search into search from the left and search from the right, respectively, the first one on the left finds the number we need and the one on the right finds the number we need. We set the return value to be of type int, if not found we return -1. Modifications can only be made when the elements we need are found.
Insertion : We divide it into left insertion and right insertion. Left insertion has the same logic as normal insertion, so the default is also left insertion. Right insertion is only different from left insertion, and the code implementation logic is exactly the same.
Modification : Modification is carried out through the subscript of the element we found. If it is not found, it cannot be modified.
Here is our test function:

void test2()//进行插入,查询,修改
{
    
    
	SL sl;
	Initialization(&sl);//初始话顺序表
	Popback(&sl, 1);//进行头插
	Popback(&sl, 2);
	Popback(&sl, 2);
	Popback(&sl, 2);
	Popback(&sl, 3);
	printf("修改前:");
	print(&sl);
	if (-1 != Seeklift(&sl, 2))//左查找
	{
    
    
		printf("左查找查到的下标:%d\n", Seeklift(&sl, 2));
		Modify(&sl, Seeklift(&sl, 2), 7);//修改
		printf("修改后:");
		print(&sl);
	}
	if (-1 != Seekright(&sl, 2))//右查找
	{
    
    
		printf("右查找查到的下标:%d\n", Seekright(&sl, 2));
		Modify(&sl, Seekright(&sl, 2), 9);
		printf("修改后:");
		print(&sl);
	}
	Insertpos(&sl, 3, 8);//按数组位置插入
	printf("按数组位置插入后:");
	print(&sl);
	Insertpos(&sl, Seeklift(&sl, 2), 3);//在元素左插入
	printf("在元素左插入后:");
	print(&sl);
	Insertright(&sl, Seeklift(&sl, 2), 4);//在元素右插入
	printf("在元素右插入后:");
	print(&sl);
	Destroy1(&sl);
}
int main()
{
    
    
	test2();
	return 0;
}

The logic of our test is to first insert 5 elements, perform left and right searches and modify them, and finally insert left and right.
insert image description here

The ascending and descending sorting of the sequence table and the return of the number of elements

We all use bubble sorting for sorting here, and we will transform it into a sorting method with a better algorithm when we wait for the sorting chapter. The only difference between ascending sort and descending sort here is the difference in the way we judge the size. The number of elements we return is to directly return the total position of the subscript of our structure elements, which is also the total number of our elements .

void Sortmax(SL* sl)//升排序
{
    
    
	assert(sl);
	//冒泡排序
	int i, j, temp;
	for (i = 1; i < sl->position; i++)
	{
    
    
		for (j = 0; j < sl->position - i; j++)
		{
    
    
			if (sl->arr[j] > sl->arr[j + 1])
			{
    
    
				temp = sl->arr[j];
				sl->arr[j] = sl->arr[j + 1];
				sl->arr[j + 1] = temp;
			}
		}
	}
}
void Sortmin(SL* sl)//降排序
{
    
    
	assert(sl);
	//冒泡排序
	int i, j, temp;
	for (i = 1; i < sl->position; i++)
	{
    
    
		for (j = 0; j < sl->position - i; j++)
		{
    
    
			if (sl->arr[j] < sl->arr[j + 1])
			{
    
    
				temp = sl->arr[j];
				sl->arr[j] = sl->arr[j + 1];
				sl->arr[j + 1] = temp;
			}
		}
	}
}
int Size(const SL *sl)//返回顺序表中元素个数
{
    
    
	assert(sl);
	return sl->position;
}

Here is our test code:

void test3()//进行升降排序
{
    
    
	SL* sl;
	sl = InitializationList();//初始话顺序表
	Popback(sl, 1);
	Popback(sl, 5);
	Popback(sl, 3);
	Popback(sl, 4);
	Popback(sl, 2);
	printf("排序前:");
	print(sl);
	Sortmax(sl);//升序排列
	printf("升序后:");
	print(sl);
	Sortmin(sl);//降序排列
	printf("降序后:");
	print(sl);
	printf("元素总个数:%d", Size(sl));
	Destroy2(sl);
}
int main()
{
    
    
	test3();
	return 0;
}

insert image description here
Here we use the second initialization method, so there is no need to add address symbols for parameter passing. The destruction function is also used second to prevent memory leaks.

Consolidation of Sequence Lists

For the merging of sequence tables, we merge in ascending order, and also merge two ascending sequence tables.
Here's our thinking:

SL* Merge(const SL* sl1,const SL* sl2)//合并两个有序的顺序表
{
    
    
	assert(sl1 && sl2);
	SL* sl = (SL*)malloc(sizeof(SL));
	sl->position = 0;
	int i = 0;//用来访问数组中的元素
	int j = 0;
	while (i < sl1->position &&  j < sl2->position)//当任意一个数组中的元素到达尾部时结束循环
	{
    
    
		if (sl1->arr[i] <= sl2->arr[j])//判断数组中的元素大小,谁小谁进行尾插
		{
    
    
			Pushback(sl, sl1->arr[i]);
			i++;
		}
		else
		{
    
    
			Pushback(sl, sl2->arr[j]);
			j++;
		}
	}
	if (i >= sl1->position)//判断哪一个数组到达了尾部,把没到达尾部的数组元素进行尾插
	{
    
    
		while(j < sl2->position)
		{
    
    
			Pushback(sl, sl2->arr[j]);
			j++;
		}
	}
	else
	{
    
    
		while (i < sl1->position)
		{
    
    
			Pushback(sl, sl1->arr[i]);
			i++;
		}
	}
	return sl;
}

The idea of ​​merging is to create a structure first, then compare the arrays in the two structures, and insert the smaller one into the structure we created. Then when the elements of one sequence table are used up, all the elements in another sequence table are inserted into the structure we created.
Here is our test code:

void test4()//合并两个有序的顺序表
{
    
    
	SL *sl;
	SL sl1 = {
    
     3,{
    
    1,6,7}};
	SL sl2 = {
    
     3,{
    
    2,3,5}};
	printf("s1:");
	print(&sl1);
	printf("s2:");
	print(&sl2);
	sl =  Merge(&sl1, &sl2);//合并两个有序的顺序表
	printf("合并后:");
	print(sl);
	Destroy2(sl);
	Destroy1(&sl1);
	Destroy1(&sl2);
}
int main()
{
    
    
	test4();
	return 0;
}

insert image description here

1. Dynamic realization of sequence table

Creation of sequence table

The essence of the dynamic implementation of the sequence table is realized through pointers.

typedef int datatype;
typedef struct SList//定义顺序表的结构体
{
    
    
	datatype* num;//数据类型的指针
	int sz;//数据元素的个数
	int max;//数据元素的最大个数
}TSL;

Here we change the previous array to the corresponding pointer type, but add an additional maximum number of elements. The maximum number of elements is used to judge whether our current storage is full. If the storage is full, it will be expanded. .

Initialization, printing and destruction of sequence table

void InitIalization(TSL* sl)//初始话顺序表
{
    
    
	sl->max = 4;//数据初始元素最大为4个
	sl->sz = 0;//数据的起始元素为0个
	sl->num = (datatype*)malloc(sizeof(datatype) * sl->max);
}

Here we set the initial capacity to 4. When the number of our elements is the same as our capacity, we will expand the capacity. Here we only write the initialization code, and the printing and destruction codes are exactly the same as the static implementation.

Sequence table addition and deletion

void Expansion(TSL* sl)//进行扩容
{
    
    
	datatype* sl1 = (datatype*)realloc(sl->num, sizeof(datatype) * (sl->max * 2));
	{
    
    
		if (sl1 == NULL)//判断是否开辟空间成功
		{
    
    
			perror("sl1 err\n");//开辟失败进行报错
			return;
		}
		else
		{
    
    
			sl->num = sl1;
			sl->max *= 2;//更改容量的大小
		}
	}
}
void PopBack(TSL* sl, datatype n)//头插
{
    
    
	assert(sl);
	if (sl->sz == sl->max)//判断空间是否已满,满则扩容
	{
    
    
		Expansion(&sl);//传递的是sl的地址,不是sl存放的地址
	}
	int i = 0;
	for (i = sl->sz; i > 0; i--)
	{
    
    
		sl->num[i] = sl->num[i - 1];//把插入元素后的前一个元素向后移动
	}
	sl->num[0] = n;//把数组中的一个元素设置为传入的值
	sl->sz++;//元素位置向后移动
}

Here we can see that the added code logic is exactly the same as the static one, except that there is an additional expansion operation.
Note: We should pay attention that the capacity increase may fail, so we cannot directly use our address, but create a structure first, and then assign our creation to our original structure after the creation is successful.
Here we only demonstrate the code of head plugging. The logic of tail plugging is the same as static, but the judgment code is replaced with the judgment of whether to expand.
Here is the demo code:

void test5()
{
    
    
	TSL sl;
	InitIalization(&sl);//初始话顺序表
	PopBack(&sl, 4);
	PopBack(&sl, 3);
	PopBack(&sl, 2);
	PopBack(&sl, 1);
	Print(&sl);
	PushBack(&sl, 5);
	PushBack(&sl, 6);
	PushBack(&sl, 7);
	PushBack(&sl, 8);
	Print(&sl);
	PopFornt(&sl);
	Print(&sl);
	PushFornt(&sl);
	Print(&sl);
	DEstroy(&sl);
}
int main()
{
    
    
	test5();
}

insert image description here

Summary of the Dynamic Sequence Table

The dynamic sequence table just adds an expansion function to the place where it is judged whether it is full. The other codes are exactly the same as the static ones, and the ideas are also the same. We replace the static arrays with corresponding pointers, and can expand the capacity through dynamic development. . Our expansion is to increase the capacity of the pointer in the structure, not to increase the capacity of the structure itself.

1. Dynamic code of sequence table

dynamic test code

//main1.c 动态测试代码
#include"main1.h"
void test5()
{
    
    
	TSL sl;
	InitIalization(&sl);//初始话顺序表
	PopBack(&sl, 4);
	PopBack(&sl, 3);
	PopBack(&sl, 2);
	PopBack(&sl, 1);
	Print(&sl);
	PushBack(&sl, 5);
	PushBack(&sl, 6);
	PushBack(&sl, 7);
	PushBack(&sl, 8);
	Print(&sl);
	PopFornt(&sl);
	Print(&sl);
	PushFornt(&sl);
	Print(&sl);
	DEstroy(&sl);
}
void test6()
{
    
    
	TSL sl;
	InitIalization(&sl);//初始话顺序表
	PopBack(&sl, 3);
	PopBack(&sl, 2);
	PopBack(&sl, 2);
	PopBack(&sl, 2);
	PopBack(&sl, 1);
	Print(&sl);
	if (-1 != SeekLift(&sl, 2))//左查找
	{
    
    
		printf("%d\n", SeekLift(&sl, 2));
		MODify(&sl, SeekLift(&sl, 2), 20);//修改
		Print(&sl);
	}
	if (-1 != SeekRight(&sl, 2))//右查找
	{
    
    
		printf("%d\n", SeekRight(&sl, 2));
		MODify(&sl, SeekRight(&sl, 2), 200);
		Print(&sl);
	}
	InsertPos(&sl, 3, 8);//按数组位置插入
	Print(&sl);
	InsertPos(&sl, SeekLift(&sl, 2), 33);//在元素左插入
	Print(&sl);
	InsertRight(&sl, SeekLift(&sl, 2), 44);//在元素右插入
	Print(&sl);
	printf("%d\n", SIze(&sl));
	DEstroy(&sl);
}
void test7()
{
    
    
	TSL sl;
	InitIalization(&sl);//初始话顺序表
	PopBack(&sl, 1);
	PopBack(&sl, 5);
	PopBack(&sl, 3);
	PopBack(&sl, 4);
	PopBack(&sl, 2);
	Print(&sl);
	SortMax(&sl);//升序排列
	Print(&sl);
	SortMin(&sl);//降序排列
	Print(&sl);
	DEstroy(&sl);
}
void test8()
{
    
    
	TSL* sl;
	TSL sl1;
	InitIalization(&sl1);//初始话顺序表
	TSL sl2;
	InitIalization(&sl2);//初始话顺序表
	PushBack(&sl1, 1);
	PushBack(&sl1, 6);
	PushBack(&sl1, 7);
	PushBack(&sl2, 2);
	PushBack(&sl2, 3);
	PushBack(&sl2, 5);
	Print(&sl1);
	Print(&sl2);
	sl = MErge(&sl1, &sl2);//合并两个有序的顺序表
	Print(sl);
	DEstroy(sl);
	DEstroy(&sl1);
	DEstroy(&sl2);
}
int main()
{
    
    
	test5();
	test6();
	test7();
	test8();
	return 0;
}

Dynamically implement the header file

//main1.h  动态头文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define MAX 10
typedef int datatype;
typedef struct SList//定义顺序表的结构体
{
    
    
	datatype* num;//数据类型的指针
	int sz;//数据元素的个数
	int max;//数据元素的最大个数
}TSL;
void InitIalization(TSL* sl);//初始话顺序表
void PopBack(TSL* sl, datatype n);//头插
void PopFornt(TSL* sl);//头删
void PushBack(TSL* sl, datatype n);//尾插
void PushFornt(TSL* sl);//尾删
int SeekLift(const TSL* sl, datatype n);//左查找
int SeekRight(const TSL* sl, datatype n);//右查找
void MODify(TSL* sl, int n, datatype num);//修改
void InsertPos(TSL* sl, int n, datatype num);//按数组位置插入,在元素左插入
void InsertRight(TSL* sl, int n, datatype num);//在元素右插入
void SortMax(TSL* sl);//升排序
void SortMin(TSL* sl);//降排序
int SIze(const TSL* sl);//返回顺序表中元素个数
TSL* MErge(TSL* sl1, TSL* sl2);//合并两个有序的顺序表
void Print(const TSL* sl);//打印顺序表
void DEstroy(TSL* sl);//销毁顺序表

Implementation of dynamic concrete functions

//test1.c  动态具体函数的实现
#include"main1.h"
void InitIalization(TSL* sl)//初始话顺序表
{
    
    
	sl->max = 4;//数据初始元素最大为4个
	sl->sz = 0;//数据的起始元素为0个
	sl->num = (datatype*)malloc(sizeof(datatype) * sl->max);
}
void Expansion(TSL* sl)//进行扩容
{
    
    
	datatype* sl1 = (datatype*)realloc(sl->num, sizeof(datatype) * (sl->max * 2));
	{
    
    
		if (sl1 == NULL)//判断是否开辟空间成功
		{
    
    
			perror("sl1 err\n");//开辟失败进行报错
			return;
		}
		else
		{
    
    
			sl->num = sl1;
			sl->max *= 2;//更改容量的大小
		}
	}
}
void PopBack(TSL* sl, datatype n)//头插
{
    
    
	assert(sl);
	if (sl->sz == sl->max)//判断空间是否已满,满则扩容
	{
    
    
		Expansion(sl);
	}
	int i = 0;
	for (i = sl->sz; i > 0; i--)
	{
    
    
		sl->num[i] = sl->num[i - 1];//把插入元素后的前一个元素向后移动
	}
	sl->num[0] = n;//把数组中的一个元素设置为传入的值
	sl->sz++;//元素位置向后移动
}
void PopFornt(TSL* sl)//头删
{
    
    
	assert(sl);
	int i = 0;
	for (i = 0; i < sl->sz; i++)
	{
    
    
		sl->num[i] = sl->num[i + 1];
	}
	sl->sz--;
}
void PushBack(TSL* sl, datatype n)//尾插
{
    
    
	assert(sl);
	if (sl->sz == sl->max)
	{
    
    
		Expansion(sl);
	}
	sl->num[sl->sz] = n;
	sl->sz++;
}
void PushFornt(TSL* sl)//尾删
{
    
    
	assert(sl);
	sl->sz--;
}
int SeekLift(const TSL* sl, datatype n)//左查找
{
    
    
	assert(sl);
	int i = 0;
	for (i = 0; i < sl->sz; i++)
	{
    
    
		if (sl->num[i] == n)
		{
    
    
			return i + 1;//数组下标从0开始,所以返回位置进行加1
		}
	}
	return -1;
}
int SeekRight(const TSL* sl, datatype n)//右查找
{
    
    
	assert(sl);
	int i = sl->sz - 1;
	for (; i > 0; i--)
	{
    
    
		if (sl->num[i] == n)
		{
    
    
			return i + 1;
		}
	}
	return -1;
}
void MODify(TSL* sl, int n, datatype num)//修改
{
    
    
	assert(sl);
	sl->num[n - 1] = num;
}
void InsertPos(TSL* sl, int n, datatype num)//按数组位置插入,在元素左插入
{
    
    
	assert(sl);
	//判断数组中是否还有空间
	if (sl->sz == sl->max)
	{
    
    
		Expansion(sl);
	}
	int sum = sl->sz;//创建一个变量等于数组中插入元素后的位置
	for (; sum > n - 1; sum--)//把坐标还原为数组的下标
	{
    
    
		sl->num[sum] = sl->num[sum - 1];//把插入元素后的前一个元素向后移动
	}
	sl->num[n - 1] = num;//把数组中的一个元素设置为传入的值
	sl->sz++;//元素位置向后移动
}
void InsertRight(TSL* sl, int n, datatype num)//在元素右插入
{
    
    
	assert(sl);
	//判断数组中是否还有空间
	if (sl->sz == sl->max)
	{
    
    
		Expansion(sl);
	}
	int sum = sl->sz;//创建一个变量等于数组中插入元素后的位置
	for (; sum > n ; sum--)//把坐标还原为数组的下标
	{
    
    
		sl->num[sum] = sl->num[sum - 1];//把插入元素后的前一个元素向后移动
	}
	sl->num[n] = num;//把数组中的一个元素设置为传入的值
	sl->sz++;//元素位置向后移动
}
void SortMax(TSL* sl)//升排序
{
    
    
	assert(sl);
	//冒泡排序
	int i, j, temp;
	for (i = 1; i < sl->sz; i++)
	{
    
    
		for (j = 0; j < sl->sz - i; j++)
		{
    
    
			if (sl->num[j] > sl->num[j + 1])
			{
    
    
				temp = sl->num[j];
				sl->num[j] = sl->num[j + 1];
				sl->num[j + 1] = temp;
			}
		}
	}
}
void SortMin(TSL* sl)//降排序
{
    
    
	assert(sl);
	//冒泡排序
	int i, j, temp;
	for (i = 1; i < sl->sz; i++)
	{
    
    
		for (j = 0; j < sl->sz - i; j++)
		{
    
    
			if (sl->num[j] < sl->num[j + 1])
			{
    
    
				temp = sl->num[j];
				sl->num[j] = sl->num[j + 1];
				sl->num[j + 1] = temp;
			}
		}
	}
}
int SIze(const TSL* sl)//返回顺序表中元素个数
{
    
    
	assert(sl);
	return sl->sz;
}
TSL* MErge(TSL* sl1, TSL* sl2)//合并两个有序的顺序表
{
    
    
	assert(sl1 && sl2);
	TSL* sl = (TSL*)malloc(sizeof(TSL));
	if (sl == NULL)//判断是否为空
	{
    
    
		perror("malloc: ");//报错且退出
		return;
	}
	InitIalization(sl);
	int i = 0;//用来访问数组中的元素
	int j = 0;
	while (i < sl1->sz && j < sl2->sz)//当任意一个数组中的元素到达尾部时结束循环
	{
    
    
		if (sl1->num[i] <= sl2->num[j])//判断数组中的元素大小,谁小谁进行尾插
		{
    
    
			if (sl->sz == sl->max)
			{
    
    
				Expansion(sl);
			}
			PushBack(sl, sl1->num[i]);
			i++;
		}
		else
		{
    
    
			if (sl->sz == sl->max)
			{
    
    
				Expansion(sl);
			}
			PushBack(sl, sl2->num[j]);
			j++;
		}
	}
	if (i >= sl1->sz)//判断哪一个数组到达了尾部,把没到达尾部的数组元素进行尾插
	{
    
    
		while (j < sl2->sz)
		{
    
    
			if (sl->sz == sl->max)
			{
    
    
				Expansion(sl);
			}
			PushBack(sl, sl2->num[j]);
			j++;
		}
	}
	else
	{
    
    
		while (i < sl1->sz)
		{
    
    
			if (sl->sz == sl->max)
			{
    
    
				Expansion(sl);
			}
			PushBack(sl, sl1->num[i]);
			i++;
		}
	}
	return sl;
}
void Print(const TSL* sl)//打印顺序表
{
    
    
	int i = 0;
	for (i = 0; i < sl->sz; i++)
	{
    
    
		printf("%d ", sl->num[i]);
	}
	printf("\n");
}
void DEstroy(TSL* sl)//销毁顺序表
{
    
    
	assert(sl);
	free(sl->num);
	sl->num = NULL;
	sl->max = 0;
	sl->sz = 0;
}

Summarize

You can compare the difference between static and dynamic. Dynamic is just a slight improvement on the basis of static, adding an expansion function, and the others are exactly the same. Next, we will use a small project to deepen our impression of the sequence table. is our first data structure, and we will use it to compare with the linked list behind. Learning the advantages and disadvantages of each structure is what we choose the optimal solution on different problems.

Guess you like

Origin blog.csdn.net/2301_76986069/article/details/131957751