[Data Structure Elementary] Sequence Table

Table of contents

Static Sequence Table

Dynamic Sequence Table

initialization

 destroy

tail plug

​Edit end delete

plug

head delete

Insert

erase

 find find


The sequence table is a linear structure in which data elements are sequentially stored in a storage unit with continuous physical addresses , and is generally stored in an array . Add, delete, check and modify data on the array .

Static Sequence Table

Define the structure:

#define N 10//方便修改长度
typedef int SLDateType//方便修改类型
typedef struct SeqList//简化代码
{
	SLDateType a[N];
	size_t  size;
}SL;

Usually the data we need to store is unknown , so we generally use a dynamic sequence table instead of a static sequence table.

Dynamic Sequence Table

typedef struct SeqList
{
	SLDateType *a;//指向数组首元素
	size_t  size;//实际存储数据
    size_t capacity;//数组容量,满则扩容
}SL;

initialization

void SLInit(SL* s)//初始化,不然可能存在随机值
{
	s->a = nullptr;
	s->capacity = s->size = 0;
}

Note that the formal parameter must be passed by pointer or reference to change the value of the original object. ( the actual parameter is a copy of the formal parameter )

 destroy

After leaving the scope, we have to destroy the operation to avoid memory leaks

void SLDestory(SL* s)//销毁
{
	if (s->a)
	{
		free(s->a);
		s->a = nullptr;
		s->capacity = s->size = 0;
	}
}

tail plug

 The implementation of the tail plug is very simple. It is necessary to pay attention to the expansion. Here, the expansion can be doubled , because frequent expansion is costly .

When we use realloc for expansion, if the pointer is empty, its function is equivalent to malloc

The following paragraph: If the expansion fails, a null pointer will be returned

If you want to avoid the consequences of being empty, you can use an intermediate variable to receive its return value.

void SLPushBack(SL* s, SLDateType x)//尾插
{
	if (s->size == s->capacity)//扩容
	{
		size_t newCapacity = s->capacity == 0? 4: s->capacity * 2;
		SLDateType *tmp =(SLDateType*)realloc(s->a, newCapacity*sizeof(SLDateType));//原地或异地扩
		if (tmp == nullptr)
		{
			perror("reaaloc fail");
			exit(-1);
		}
		s->a = tmp;
		s->capacity = newCapacity;
	}
	s->a[s->size] = x;
	s->size++;
}

 tail delete

Let me ask you a question first, does tail deletion need to set the deleted position to 0?

The answer is definitely not, we can change the size of the size to make it output the previous size data, and it will be overwritten when new data comes in. Is it just to reduce the size by 1? 

Here I only do size --, you can see that there is no problem 

 There is a very confusing error here, which can only be detected when you use the free that is being destroyed or write to out-of-bounds memory ( reading is basically not detected ). Because the compiler's check for out-of-bounds is a spot-check behavior . (Here I use an unsigned integer to modify the size, so no error will be reported when free.)

We can check with aseert or return directly

void SLPopBack(SL* s )//尾删
{
	/*if (s->size == 0)
{
return;
}*/
    assert(s);
	assert(s->size>0);
	s->size--;
}

In order to avoid the dereference of the null pointer, we can also make such an assertion in front of the previous function:

	assert(s);

plug

Because plugging also involves capacity expansion, we can encapsulate the code that implements capacity expansion into a function.

void SLCheckCapacity(SL* s)
{
	assert(s);
	if (s->size == s->capacity)//扩容
	{
		size_t newCapacity = s->capacity == 0 ? 4 : s->capacity * 2;
		SLDateType* tmp = (SLDateType*)realloc(s->a, newCapacity * sizeof(SLDateType));//原地或异地扩
		if (tmp == nullptr)
		{
			perror("reaaloc fail");
			exit(-1);
		}
		s->a = tmp;
		s->capacity = newCapacity;
	}
}

The data must be moved from the back to the front of the head plug , otherwise the data will be overwritten   

void SLPushFront(SL* s, SLDateType x)//头插
{
	assert(s);
	SLCheckCapacity(s);
	//挪动
	int end = s->size - 1;
	while (end >=0)
	{
		s->a[end + 1] = s->a[end];
		end--;
	}
	s->a[0] = x;
	s->size++;

}

 The time complexity of tail insertion is O(n) and head insertion is O(n^2).

head delete

void SLPopFront(SL* s)//头删
{
	assert(s);//从前往后
	assert(s->size > 0);//防止越界
	int begin = 1;
	while (begin < s->size )
	{
		//s->a[begin] = s->a[begin + 1];
		s->a[begin-1] = s->a[begin];
		begin++;
	}
	s->size--;
}

 Note that the initial point of begin here should be 1 to avoid crossing the boundary.

Insert

void SLInsert(SL* s, int pos, SLDateType x)
{
	assert(s);
	assert(pos <= s->size && pos >= 0);//可插入范围
	SLCheckCapacity(s);//插入前检查容量
	int end = s->size - 1;
	while (end >= pos)//从后往前
	{
		s->a[end + 1] = s->a[end];
		end--;
	}
	s->a[pos] = x;
	s->size++;
}

Note that pos can be the size position, which means tail insertion

Simplified head-to-tail plug-in code:

void SLPushFront(SL* s, SLDateType x)//头插
{
	SLInsert(s, 0, x);
}
void SLPushBack(SL* s, SLDateType x)//尾插
{
	SLInsert(s, s->size, x);
}

erase

According to the logic of implementing header deletion from front to back, we can implement it like this:

void  SLErase(SL* s, int pos)
{
	assert(s);
	assert(pos < s->size&& pos >= 0);
	//assert(s->size>0);
	int begin = pos + 1;
	while (begin < s->size)
	{
		s->a[begin - 1] = s->a[begin];
		begin++;
	}
	s->size--;
}

Note that when judging the pos range here, the size range is judged indirectly, so you don’t need to judge the size, by the way, when deleting the last data is different from inserting, you can insert at the size position, and the last deleted position is size-1 .

Tail delete head delete multiplexing:

void SLPopBack(SL* s )//尾删
{
	SLErase(s, s->size - 1);
}
void SLPopFront(SL* s)//头删
{
	SLErase(s, 0);
}

 find find

The search for adding, deleting, checking and modifying data is to find the corresponding array subscript and return

SLDateType SLFind(SL* s, SLDateType x)//查找
{
	assert(s);
	for (int i = 0; i < s->size; i++)
	{
		if (s->a[i] == x)
		{
			return i;
		}
	}
	return -1;//查找失败返回无效下标
}

 print function

void SLPrint(SL* s)
{
	assert(s);

	for (int i = 0; i < s->size; ++i)
	{
		printf("%d ", s->a[i]);
	}
	printf("\n");
}

We can also specify to search from a certain location, just add a parameter. For example, delete all elements containing 5:

 menu

This is a simple menu template. You can try it yourself. It should be noted that when writing a program, you usually debug while writing , and it is actually inconvenient to debug with the menu.

void menu()
{
	printf("***********************************************\n");
	printf("1、尾插数据 2、尾删数据\n");
	printf("3、头插数据 4、头删数据\n");
	printf("5、打印数据 -1、退出\n");
	printf("***********************************************\n");
}
int main()
{
	SL s;
	SLInit(&s);
	int option = 0;
	int n = 0;
	do
	{
		menu();
		printf("请输入您的操作: ");
		scanf("%d", &option);
		switch (option)
		{
		case 1:
			printf("请输入尾插数据,以-1结束>");
			scanf("%d", &n);
			/*while (scanf("%d", &n) != EOF)*/
			while (n != -1)//-1不存入数据
			{
				SLPushBack(&s, n);
			}
			break;
		case 2:
			SLPopBack(&s);
			break;
		case 3:
			//
			break;
		case 4:
			//
			break;
		case 5:
			SLPrint(&s);
			break;
		default: 
			printf("输入错误,请重新输入");
				break;
		}
	} while (option != -1);
	SLDestory(&s);
//SeqList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define N 10//方便修改长度
typedef int SLDateType;//方便修改类型
//typedef struct SeqList
//{
//	SLDateType a[N];
//	size_t size;
//}SL;
//动态:按需
typedef struct SeqList//简化代码
{
	SLDateType *a;
	size_t  size;
	size_t capacity;//数组容量,满则扩容
}SL;
void SLInit(SL* s);//初始化
void SLDestory(SL* s);//销毁

void SLPushBack(SL* s, SLDateType x);//尾插
void SLPopBack(SL* s);//尾删
void SLPushFront(SL* s, SLDateType x);//头插
void SLPopFront(SL* s);//头删
void SLCheckCapacity(SL* s);
void SLInsert(SL* s, int pos, SLDateType x);//插入
void  SLErase(SL* s, int pos);//删除
SLDateType SLFind(SL *s,SLDateType x,int pos);//查找
void SLPrint(SL* s);

 




//SeqList.c
#include"SeqList.h"
void SLCheckCapacity(SL* s)
{
	assert(s);
	if (s->size == s->capacity)//扩容
	{
		size_t newCapacity = s->capacity == 0 ? 4 : s->capacity * 2;
		SLDateType* tmp = (SLDateType*)realloc(s->a, newCapacity * sizeof(SLDateType));//原地或异地扩
		if (tmp == nullptr)
		{
			perror("reaaloc fail");
			exit(-1);
		}
		s->a = tmp;
		s->capacity = newCapacity;
	}
}

void SLInit(SL* s)//初始化,不然可能存在随机值
{
	assert(s);
	s->a = nullptr;
	s->capacity = s->size = 0;
}
void SLPushBack(SL* s, SLDateType x)//尾插
{
	SLInsert(s, s->size, x);
	/*assert(s);
	SLCheckCapacity(s);
	s->a[s->size] = x;
	s->size++;*/
}
void SLDestory(SL* s)//销毁
{
	assert(s);
	if (s->a)
	{
		free(s->a);
		s->a = nullptr;
		s->capacity = s->size = 0;
	}
}
void SLPopBack(SL* s )//尾删
{
	SLErase(s, s->size - 1);
	/*if (s->size == 0)
{
return;
}*/
	/*assert(s);
	assert(s->size>0);
	s->size--;*/

}
void SLPushFront(SL* s, SLDateType x)//头插
{
	SLInsert(s, 0, x);
	//assert(s);
	//SLCheckCapacity(s);
	从后往前挪动
	//int end = s->size - 1;
	//while (end >=0)
	//{
	//	s->a[end + 1] = s->a[end];
	//	end--;
	//}
	//s->a[0] = x;
	//s->size++;
	
}
void SLPopFront(SL* s)//头删
{
	SLErase(s, 0);
	//assert(s);//从前往后
	//assert(s->size > 0);//防止越界
	//int begin = 1;
	//while (begin < s->size )
	//{
	//	//s->a[begin] = s->a[begin + 1];
	//	s->a[begin-1] = s->a[begin];
	//	begin++;
	//}
	//s->size--;
}
void SLInsert(SL* s, int pos, SLDateType x)
{
	assert(s);
	assert(pos <= s->size && pos >= 0);//可插入范围
	SLCheckCapacity(s);//插入前检查容量
	int end = s->size - 1;
	while (end >= pos)//从后往前
	{
		s->a[end + 1] = s->a[end];
		end--;
	}
	s->a[pos] = x;
	s->size++;
}
void  SLErase(SL* s, int pos)
{
	assert(s);
	assert(pos < s->size&& pos >= 0);
	//assert(s->size>0);
	int begin = pos + 1;
	while (begin < s->size)
	{
		s->a[begin - 1] = s->a[begin];
		begin++;
	}
	s->size--;
}
SLDateType SLFind(SL* s, SLDateType x,int pos)//查找
{
	assert(s);
	for (int i = 0; i < s->size; i++)
	{
		if (s->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}
void SLPrint(SL* s)
{
	assert(s);

	for (int i = 0; i < s->size; ++i)
	{
		printf("%d ", s->a[i]);
	}
	printf("\n");
}

The above is the content of our sequence table

Guess you like

Origin blog.csdn.net/dwededewde/article/details/131094415