DS linear table sequence table

Foreword 

In the last issue, we introduced what data structures and algorithms are, as well as the algorithm efficiency problem, that is, what is space-time complexity~ and the calculation method of space-time complexity, as well as detailed explanations of common time-space complexity examples. In this issue, we will introduce linear The sequence table in the table~!

Introduction to the contents of this issue

What is a linear table?

The concept and classification of sequence tables

Implementation of static sequence table

Implementation of dynamic sequence table

There is a problem with the sequence table

Table of contents

Foreword 

Introduction to the contents of this issue

1. What is a linear table?

2. Sequence table

The concept and structural classification of sequence tables

3. Implementation of static sequence table

Declaration of static sequence table

Initialization of static sequence table

Destruction of static sequence list

Printing of static sequence tables

End insertion of static sequence table

Tail deletion of static sequence table

Static sequence table header

Header deletion of static sequence table

Sorting of static sequence tables

Static sequence table is inserted at pos position

The static sequence table is deleted at pos position

Static sequence table searches for specified element x

Modify the element at the specified pos position in the static sequence table

All source code:

4. Implementation of dynamic sequence table

Declaration of dynamic sequence table

Initialization of dynamic sequence table

Destruction of dynamic sequence table

Printing of dynamic sequence table

End insertion of dynamic sequence table

Tail deletion of dynamic sequence table

Dynamic sequence table header

Header deletion of dynamic sequence table

Sorting of dynamic sequence tables

Dynamic sequence table is inserted at pos position

Dynamic sequence table is deleted at pos position

Find the specified element x in the dynamic sequence table

Modify the element at the specified pos position in the dynamic sequence table

All source code:

5. Problems with sequence tables


1. What is a linear table?

Linear List is a set of N data elements with the same characteristics! A linear table is logically a linear structure, that is, a continuous line, but its physical structure is not necessarily continuous~! Common linear lists include: sequence list, linked list, stack, queue, string, etc.

Why is it said that the logical structure is continuous, but the physical structure is not necessarily continuous? We introduced something called the self-reference of a structure in the issue of detailed explanation of C language custom types. We said at that time that it was a linked list, and its development must be dynamically opened on the heap ( Randomly assigned by the operating system)~! So the entire linked list may not be continuous! When he was writing the address book, it was actually a sequence list! Let me draw a picture to explain the above sentence:

2. Sequence table

The concept and structural classification of sequence tables

Sequence table is a linear structure that uses a section of storage units with consecutive physical addresses to store data elements in sequence. ! Under normal circumstances, array storage is used, and various operations are performed on the array, that is, addition, deletion, checking and modification (through various interfaces)!

Sequence tables can be divided into: static sequence tables and dynamic sequence tables

Static sequence table: the number of stored data is fixed

Dynamic sequence table: The number of stored data is not fixed and can be expanded if it is not enough.

OK, let’s write one look and one look each:

Static sequence table:

#define MAX 10
typedef int SLDataType;
typedef struct SeqList
{
	SLDataType data[MAX];
	int size;//顺序表的元素个数
}SeqList;

Dynamic sequence table:

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* data;
	int size;//顺序表的元素个数
	int capacity;//顺序表的容量
}SeqList;

You may still have some questions here, for example, isn’t it just adding, deleting, checking, and modifying an array? Can't I just operate directly on the array? OK, then how do you know how many elements are currently in your array when you are operating? How to judge??? There seems to be no way! You can only define a variable to record the number of elements in it, so why not just use the sequence table? ? ? Right, it’s one step, you just need to do the rest and don’t worry~! Another thing is: the storage of sequence tables must be continuous, you can only store them next to each other, but you may not be able to store arrays in different locations! ! ! !

3. Implementation of static sequence table

OK, we still use multi-file programming: declarations and so on are placed in .h files, implementations are in .c files, and tests are in test.c

At the beginning we need to have a sequence list:

Declaration of static sequence table

#define MAX 15
typedef int SeqDataType;

typedef struct SeqList
{
	SeqDataType data[MAX];
	int size;
}SL;

Initialization of static sequence table

The bottom layer here is an array! We can use a loop to do it, or we can directly use memset to initialize. We initially set each element in the array to 0, and the size is also set to 0;

//初始化
void SLInit(SL* ps)
{
	assert(ps);

	memset(ps->data, 0, sizeof(int) * MAX);
	ps->size = 0;
}

Here you may be thinking why do we need to use pointers for formal parameters? Here is the same problem: the problem of formal parameters and actual parameters. Changes in formal parameters do not affect the actual parameters! To change the actual parameters externally, you must pass a pointer!

Destruction of static sequence list

If there is initialization, there must be destruction~! So how to destroy this static sequence table? Since it is opened on the stack and free cannot be used, we only need to set its array content to 0 and its size to 0~! (Size can also be set to 0, don’t let him access it), just call the initialization directly here:

//销毁
void SLDestory(SL* ps)
{
	assert(ps);
	SLInit(ps);
}

In order to directly view the results later, we can implement a printing function here:

Printing of static sequence tables

//打印
void SLPrint(const SL* ps)
{
	assert(ps);

	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->data[i]);
	}

	printf("\n");
}

End insertion of static sequence table

Tail insertion is relatively simple, because size records the number of valid elements of the array. Adding an element to the array will ++ the size, so size is the subscript of the next element, so we only need to add Just insert at the position, but since the storage size is fixed, you have to judge whether it can be inserted before inserting. If the sequence table is full, what else can you insert?

//尾插
void SLPushBack(SL* ps, SeqDataType x)
{
	assert(ps);
	
	if (ps->size == MAX)
	{
		printf("顺序表已满无法插入!\n");
		exit(-1);
	}
	//assert(MAX == ps->size);

	ps->data[ps->size] = x;
	ps->size++;
}

Of course, there are two situations when the judgment here is full, "gentle inspection" and "violent inspection". In fact, I personally prefer violent inspection. If it is full, the program will be terminated directly, and we also introduced the assert assertion earlier. Failure will also tell you which line of which file the problem occurred~! Of course, if you pay attention to humanity, if is better~! It’s all available here!

Tail deletion of static sequence table

Tail deletion is as simple as tail insertion. Since when you access it, it is less than size, so you only need to let size--. At this time, you will not be able to access the last element~! This is equivalent to deleting the tail~! Of course, you have to judge when deleting. If the sequence table is already empty, it seems unreasonable for you to delete it...! So don’t delete it when the sequence list is empty. So when is the sequence list empty? We have said that size is the subscript of the next element. When the subscript of the next element is 0, it means that the following table of the current element is -1, but the subscript cannot be -1, so it can only indicate the current effective element. The number is 0, and size does not have ++, so when szie == 0, it means that the sequence table cannot be deleted once it is empty~!

void SLPopBack(SL* ps)
{
	assert(ps);

	if (ps->size  == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}

	ps->size--;
}

Of course, you can also use violence to check~!

OK, let’s develop a good habit and write two tests:

There is no problem with tail insertion. Let’s take a look at tail deletion:

Static sequence table header

Since it is inserting, you need to consider whether it is full. If it is full, exit directly or insert~!

//头插
void SLPushFront(SL* ps, SeqDataType x)
{
	assert(ps);

	if (ps->size == MAX)
	{
		printf("顺序表已满无法插入!\n");
		exit(-1);
	}

	int i = 0;
	for (i = ps->size; i > 0; i--)
	{
		ps->data[i] = ps->data[i - 1];
	}

	ps->data[i] = x;
	ps->size++;
}

Header deletion of static sequence table

When deleting, as before, be sure to consider the situation that the sequence table is empty~! If it is empty, exit directly without deleting it~!

//头删
void SLPopFront(SL* ps)
{
	assert(ps);

	if (ps->size == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}
	//assert(ps->size);

	for (int i = 0; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i+1];
	}

	ps->size--;
}

OK, let’s test it:

OK, there is no problem in deleting the header plug~!

Sorting of static sequence tables

The sorting we use here uses qsort. Of course, other sorting can also be used~!

int cmp(const void* a, const void* b)
{
	return *(int*)a - *(int*)b;
}

//排序
void SLSort(SL* ps)
{
	assert(ps);
	assert(ps->size);

	qsort(ps->data, ps->size, sizeof(int), cmp);
}

Static sequence table is inserted at pos position

Insertion must determine whether it is full. Here we also need to pay attention to the rationality of pos. Because pos is a position, not a subscript, the difference between pos and the array subscript is 1 (as shown below). If the position of pos is less than 1, the position of the sequence table is How can something starting from 1 be less than 1? It is unreasonable to exit directly. pos is greater than or equal to the maximum length of the sequence list. This is also unreasonable~! The difference between the position of the sequence table and the subscript of the array is 1, and you are both greater than or equal to the maximum subscript (assuming that it is full and cannot be inserted, even if the sequence table is not satisfied, random insertion is not allowed)

//在pos位置插入x
void SLInsert(SL* ps, int pos, SeqDataType x)
{
	assert(ps);

	if (pos < 1 || pos >= MAX || ps->size >= MAX)
	{
		printf("pos非法或顺序表已满!\n");
		exit(-1);
	}

	int i = 0;
	for (i = ps->size; i >= pos; i--)
	{
		ps->data[i] = ps->data[i-1];
	}
	ps->data[pos-1] = x;
	ps->size++;
}

The static sequence table is deleted at pos position

Delete the situation where it must be judged whether it is already empty~! And like the above, pos cannot be less than 1, delete things outside the sequence table and exit directly. Also, the deleted position is an array sum method but not a valid data area of ​​the sequence table, which cannot be deleted~!

//删除pos位置
void SLErase(SL* ps, int pos)
{
	assert(ps);

	
	if (ps->size == 0 || pos < 1 || pos >= MAX || pos >= ps->size)
	{
		printf("pos非法或顺序表为空无法删除!\n");
		exit(-1);
	}

	for (int i = pos-1; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}

	ps->size--;
}

OK, let’s test it out:

OK, sorting and inserting and deleting at pos are all normal~! Let’s write down a few:

Static sequence table searches for specified element x

This interface is very simple to implement. You only need to traverse the array once (in the absence of sorting). If it is sorted, direct binary search is the most efficient~! If found, the subscript is returned; if not found, -1 is returned.


//查找指定元素x
int SLFind(SL* ps, SeqDataType x)
{
	assert(ps);

	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->data[i])
			return i;
	}

	return -1;
}

Modify the element at the specified pos position in the static sequence table

Just consider the boundaries here. You cannot exceed the maximum storage range or the valid data range of the sequence table, as well as the legality of pos itself~!

//修改顺序表pos位置的元素
void SLModif(SL* ps, int pos, SeqDataType x)
{
	assert(ps);

	if (pos >= 1 && pos <= MAX && pos <= ps->size)
	{
		ps->data[pos - 1] = x;
	}
}

OK, test it out:

All source code:

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#define MAX 5
typedef int SeqDataType;

typedef struct SeqList
{
	SeqDataType data[MAX];
	int size;
}SL;

//初始化
void SLInit(SL* ps);

//销毁
void SLDestory(SL* ps);

//打印
void SLPrint(const SL* ps);

//尾插
void SLPushBack(SL* ps, SeqDataType x);

//尾删
void SLPopBack(SL* ps);

//头插
void SLPushFront(SL* ps, SeqDataType x);

//头删
void SLPopFront(SL* ps);

//排序
void SLSort(SL* ps);

//在pos位置插入x
void SLInsert(SL* ps, int pos, SeqDataType x);

//删除pos位置
void SLErase(SL* ps, int pos);

//查找指定元素x
int SLFind(SL* ps, SeqDataType x);

//修改顺序表pos位置的元素
void SLModif(SL* ps,int pos, SeqDataType x);
#include "SeqList.h"

//初始化
void SLInit(SL* ps)
{
	assert(ps);

	memset(ps->data, 0, sizeof(int) * MAX);
	ps->size = 0;
}

//销毁
void SLDestory(SL* ps)
{
	assert(ps);
	SLInit(ps);
}

//打印
void SLPrint(const SL* ps)
{
	assert(ps);

	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->data[i]);
	}

	printf("\n");
}


//尾插
void SLPushBack(SL* ps, SeqDataType x)
{
	assert(ps);
	
	if (ps->size == MAX)
	{
		printf("顺序表已满无法插入!\n");
		exit(-1);
	}
	//assert(MAX == ps->size);

	ps->data[ps->size] = x;
	ps->size++;
}


//尾删
void SLPopBack(SL* ps)
{
	assert(ps);

	if (ps->size  == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}

	ps->size--;
}


//头插
void SLPushFront(SL* ps, SeqDataType x)
{
	assert(ps);

	if (ps->size == MAX)
	{
		printf("顺序表已满无法插入!\n");
		exit(-1);
	}

	int i = 0;
	for (i = ps->size; i > 0; i--)
	{
		ps->data[i] = ps->data[i - 1];
	}

	ps->data[i] = x;
	ps->size++;
}

//头删
void SLPopFront(SL* ps)
{
	assert(ps);

	if (ps->size == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}
	//assert(ps->size);

	for (int i = 0; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i+1];
	}

	ps->size--;
}


int cmp(const void* a, const void* b)
{
	return *(int*)a - *(int*)b;
}

//排序
void SLSort(SL* ps)
{
	assert(ps);
	assert(ps->size);

	qsort(ps->data, ps->size, sizeof(int), cmp);
}


//在pos位置插入x
void SLInsert(SL* ps, int pos, SeqDataType x)
{
	assert(ps);

	if (pos < 1 || pos >= MAX || ps->size >= MAX)
	{
		printf("pos非法或顺序表已满!\n");
		exit(-1);
	}

	int i = 0;
	for (i = ps->size; i >= pos; i--)
	{
		ps->data[i] = ps->data[i-1];
	}
	ps->data[pos-1] = x;
	ps->size++;
}

//删除pos位置
void SLErase(SL* ps, int pos)
{
	assert(ps);

	
	if (ps->size == 0 || pos < 1 || pos >= MAX || pos >= ps->size)
	{
		printf("pos非法或顺序表为空无法删除!\n");
		exit(-1);
	}

	for (int i = pos-1; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}

	ps->size--;
}


//查找指定元素x
int SLFind(SL* ps, SeqDataType x)
{
	assert(ps);

	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->data[i])
			return i;
	}

	return -1;
}


//修改顺序表pos位置的元素
void SLModif(SL* ps, int pos, SeqDataType x)
{
	assert(ps);

	if (pos >= 1 && pos <= MAX && pos <= ps->size)
	{
		ps->data[pos - 1] = x;
	}
}
#include "SeqList.h"

//测试尾插、尾删以及初始化、销毁、打印
void test1()
{
	SL s;
	SLInit(&s);

	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPrint(&s);
	SLPushBack(&s, 5);
	SLPrint(&s);

	SLPopBack(&s);
	SLPrint(&s);
	SLPopBack(&s);
	SLPrint(&s);
	SLPopBack(&s);
	SLPrint(&s);
	SLPopBack(&s);
	SLPrint(&s);
	SLPopBack(&s);
	SLPrint(&s);

	//检查是否满的时候插入是否有Bug
	SLPopBack(&s);
	SLPrint(&s);

	SLDestory(&s);
}

//测试头插、头删
void test2()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 5);
	SLPushFront(&s, 6);
	SLPrint(&s);

	//检查是在满的情况下是否有Bug
	//SLPushFront(&s, 7);
	//SLPrint(&s);

	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);

	//检查是否空的时候删除是否有Bug
	SLPopFront(&s);
	SLPrint(&s);

	SLDestory(&s);
}

//测试排序、在pos位置插入、删除pos位置
void test3()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 5);
	SLPrint(&s);

	SLSort(&s);
	SLPrint(&s);

	SLInsert(&s, 3, 4);
	SLPrint(&s);

	SLErase(&s, 1);
	SLPrint(&s);
	SLErase(&s, 3);
	SLPrint(&s);

	SLDestory(&s);
}

//测试查找指定元素和修改pos位置的元素的值
void test4()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, 1);
	SLPushFront(&s, 2);
	SLPushFront(&s, 3);
	SLPushFront(&s, 5);
	SLPrint(&s);

	int ret = SLFind(&s, 4);
	if (ret != -1)
	{
		printf("找到了,下标为: %d ", ret);
	}
	else
	{
		printf("没找到\n");
	}

	SLModif(&s, 2, 20);
	SLPrint(&s);
	SLModif(&s, 1, 10);
	SLPrint(&s);

	SLModif(&s, 4, 40);
	SLPrint(&s);

	SLDestory(&s);
}


int main()
{
	test4();
	return 0;
}

The disadvantage of the static sequence table is that its storage number is fixed. This flaw results in that there are not many application scenarios for it. How much space do you give it at the beginning? Isn’t this very difficult? If it is too large, it will be wasteful; if it is too small, it will not be enough... so its application scenarios are not many! In response to this situation, we optimize: give a little space at the beginning (or not open it), and when it is not enough, we expand it (1.5 times or 2 times each time), which effectively reduces the waste of memory~! OK, let's look at the dynamic version of the look sequence table.

4. Implementation of dynamic sequence table

Declaration of dynamic sequence table

typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* data;
	int size;//顺序表的元素个数
	int capacity;//顺序表的容量
}SeqList;

Initialization of dynamic sequence table

//初始化
void SLInit(SL* ps)
{
	assert(ps);
	ps->data = (SLDataType*)malloc(sizeof(SLDataType) * 4);
	if (!ps->data)
	{
		perror("malloc failed");
		exit(-1);//异常终止
	}

	ps->size = 0;
	ps->capacity = 4;
}

This must be checked after malloc is developed, otherwise once the development fails, it will be over~! You haven't even opened the array yet, why are you still adding, deleting, checking, and modifying there? ? ? Therefore, if the development fails, exit abnormally~!

Destruction of dynamic sequence table

//销毁
void SLDestory(SL* ps)
{
	assert(ps);

	free(ps->data);
	ps->data = NULL;
	ps->size = ps->capacity = 0;
}

Remember to leave ps-data blank at the end, otherwise it will be a wild pointer~!

Printing of dynamic sequence table


//打印
void SLPrint(SL* ps)
{
	assert(ps);

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

End insertion of dynamic sequence table

//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);

	//判断扩容
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * newcapacity);
		if (!tmp)
		{
			perror("realloc failed");
			exit(-1);
		}
		
		ps->data = tmp;
		ps->capacity = newcapacity;
	}

	ps->data[ps->size] = x;
	ps->size++;
}

Since it is dynamically developed, we do not need to consider the problem of being full and unable to insert. We only need to consider whether to expand the capacity. If the number of valid data in the sequence table == capacity, then the capacity must be expanded~!

Tail deletion of dynamic sequence table

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);

	//判断是否为空
	if (ps->size == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}

	ps->size--;
}

Tail deletion must consider the situation that the current sequence table is already empty~! Here you can also use the assertion to terminate directly once it is empty. I am a little more humane here and give a prompt, and exit abnormally~! Haha~

OK, same old thing! Write two and test two:

OK, there is no problem with inserting the end and deleting the end~! Let's go on ~!

Dynamic sequence table header

Determining whether to expand the capacity will appear multiple times here, and the code is relatively long, so we can consider encapsulating it into a function~!

//判断扩容
void JudExpan(SL* ps)
{
	assert(ps);

	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * newcapacity);
		if (!tmp)
		{
			perror("realloc failed");
			exit(-1);
		}

		ps->data = tmp;
		ps->capacity = newcapacity;
	}
}
//头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);

	JudExpan(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->data[i] = ps->data[i - 1];
	}
	ps->data[0] = x;
	ps->size++;
}

Header deletion of dynamic sequence table

Of course, the judgment when the header deletion judgment is empty can also be encapsulated into a function, but there are only two sentences here, so I did not encapsulate it into a function~!

//头删
void SLPopFront(SL* ps)
{
	assert(ps);

	//判断是否为空
	if (ps->size == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}

	for (int i = 0; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->size--;
}

OK, test it out:

OK, no problem~! Let's continue!

Sorting of dynamic sequence tables

We still use qsort provided in the C language library for sorting.

//比较函数
int cmp(const void* a, const void* b)
{
	return *(int*)a - *(int*)b;
}

//排序
void SLSort(SL* ps)
{
	assert(ps);
	qsort(ps->data, ps->size, sizeof(SLDataType), cmp);
}

Let’s just modify the head plug of Sen Gang and test it:

OK, no problem!

Dynamic sequence table is inserted at pos position

//在pos位置插入
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);

	JudExpan(ps);
	//判断pos的合法性
	if (pos > ps->capacity || pos < 1)
	{
		printf("pos非法!");
		exit(-1);
	}

	for (int i = ps->size; i >= pos; i--)
	{
		ps->data[i] = ps->data[i - 1];
	}
	ps->data[pos - 1] = x;
	ps->size++;
}

Remember to judge the legality of the POS~! ! !

Dynamic sequence table is deleted at pos position

//删除pos位置的元素
void SLErase(SL* ps, int pos)
{
	assert(ps);

	//判断是否为空
	if (ps->size == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}
	//判断pos的合法性
	if (pos < 1 || pos > ps->size)
	{
		printf("pos非法!");
		exit(-1);
	}

	for (int i = pos - 1; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->size--;
}

Still pay attention to the legality of POS! ! !

OK, test it out:

OK, no problem~!

Find the specified element x in the dynamic sequence table

This is still the same as the above and returns the subscript, otherwise it returns -1 (if it is already ordered, you can use binary search)

//查找指定元素x
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);

	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->data[i])
		{
			return i;
		}
	}

	return -1;
}

Modify the element at the specified pos position in the dynamic sequence table

//修改pos位置的值
void SLModif(SL* ps, int pos, SLDataType x)
{
	assert(ps);

	if (pos >=1 && pos <= ps->size)
	{
		ps->data[pos - 1] = x;
	}
	else
	{
		printf("pos非法!\n");
		exit(-1);
	}
}

Here you also need to pay attention to determine the legality of the POS~! ! ! Otherwise there will be problems! ! !

OK, test it out:

OK, no problem~!

All source code:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>


typedef int SLDataType;
typedef struct SeqList
{
	SLDataType* data;
	int size;//顺序表的元素个数
	int capacity;//顺序表的容量
}SL;

//初始化
void SLInit(SL* ps);

//销毁
void SLDestory(SL* ps);

//打印
void SLPrint(SL* ps);

//尾插
void SLPushBack(SL* ps, SLDataType x);

//尾删
void SLPopBack(SL* ps);

//头插
void SLPushFront(SL* ps, SLDataType x);

//头删
void SLPopFront(SL* ps);

//排序
void SLSort(SL* ps);

//在pos位置插入
void SLInsert(SL* ps, int pos, SLDataType x);

//删除pos位置的元素
void SLErase(SL* ps, int pos);

//查找指定元素x
int SLFind(SL* ps, SLDataType x);

//修改pos位置的值
void SLModif(SL* ps, int pos, SLDataType x);
#include "SeqList.h"

//初始化
void SLInit(SL* ps)
{
	assert(ps);
	ps->data = (SLDataType*)malloc(sizeof(SLDataType) * 4);
	if (!ps->data)
	{
		perror("malloc failed");
		exit(-1);//异常终止
	}

	ps->size = 0;
	ps->capacity = 4;
}

//销毁
void SLDestory(SL* ps)
{
	assert(ps);

	free(ps->data);
	ps->data = NULL;
	ps->size = ps->capacity = 0;
}

//打印
void SLPrint(SL* ps)
{
	assert(ps);

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

//判断扩容
void JudExpan(SL* ps)
{
	assert(ps);

	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * newcapacity);
		if (!tmp)
		{
			perror("realloc failed");
			exit(-1);
		}

		ps->data = tmp;
		ps->capacity = newcapacity;
	}
}

//尾插
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);

	JudExpan(ps);
	ps->data[ps->size] = x;
	ps->size++;
}

//尾删
void SLPopBack(SL* ps)
{
	assert(ps);

	//判断是否为空
	if (ps->size == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}

	ps->size--;
}

//头插
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);

	JudExpan(ps);
	for (int i = ps->size; i > 0; i--)
	{
		ps->data[i] = ps->data[i - 1];
	}
	ps->data[0] = x;
	ps->size++;
}

//头删
void SLPopFront(SL* ps)
{
	assert(ps);

	//判断是否为空
	if (ps->size == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}

	for (int i = 0; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->size--;
}

//比较函数
int cmp(const void* a, const void* b)
{
	return *(int*)a - *(int*)b;
}

//排序
void SLSort(SL* ps)
{
	assert(ps);
	qsort(ps->data, ps->size, sizeof(SLDataType), cmp);
}

//在pos位置插入
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);

	JudExpan(ps);
	//判断pos的合法性
	if (pos > ps->capacity || pos < 1)
	{
		printf("pos非法!");
		exit(-1);
	}

	for (int i = ps->size; i >= pos; i--)
	{
		ps->data[i] = ps->data[i - 1];
	}
	ps->data[pos - 1] = x;
	ps->size++;
}

//删除pos位置的元素
void SLErase(SL* ps, int pos)
{
	assert(ps);

	//判断是否为空
	if (ps->size == 0)
	{
		printf("顺序表为空无法删除!\n");
		exit(-1);
	}
	//判断pos的合法性
	if (pos < 1 || pos > ps->size)
	{
		printf("pos非法!");
		exit(-1);
	}

	for (int i = pos - 1; i < ps->size; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->size--;
}


//查找指定元素x
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);

	for (int i = 0; i < ps->size; i++)
	{
		if (x == ps->data[i])
		{
			return i;
		}
	}

	return -1;
}

//修改pos位置的值
void SLModif(SL* ps, int pos, SLDataType x)
{
	assert(ps);

	if (pos >=1 && pos <= ps->size)
	{
		ps->data[pos - 1] = x;
	}
	else
	{
		printf("pos非法!\n");
		exit(-1);
	}
}
#include "SeqList.h"

//测试尾插、尾删
void test()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPrint(&s);
	//检查扩容
	SLPushBack(&s, 5);
	SLPrint(&s);

	SLPopBack(&s);
	SLPrint(&s);
	SLPopBack(&s);
	SLPrint(&s);
	SLPopBack(&s);
	SLPrint(&s);
	SLPopBack(&s);
	SLPrint(&s);
	SLPopBack(&s);
	SLPrint(&s);

	//检查是否已经为空是的删除是否有Bug
	SLPopBack(&s);
	SLPrint(&s);

	SLDestory(&s);
}

//测试头插、头删
void test2()
{
	SL s;
	SLInit(&s);

	SLPushFront(&s, -1);
	SLPushFront(&s, 3);
	SLPushFront(&s, 0);
	SLPushFront(&s, 1);
	SLPrint(&s);
	//判断扩容
	SLPushFront(&s, 10);
	SLPrint(&s);

	SLSort(&s);
	SLPrint(&s);

	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
	SLPopFront(&s);
	SLPrint(&s);
	//检查为空时删除是否有Bug
	SLPopFront(&s);
	SLPrint(&s);

	SLDestory(&s);
}

//测试在pos位置插入、删除
void test3()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPrint(&s);

	SLInsert(&s, 4, 10);
	SLPrint(&s);
	SLInsert(&s, 4, -1);
	SLPrint(&s);
	//SLInsert(&s, 20, 7);
	//SLPrint(&s);

	SLErase(&s, 1);
	SLPrint(&s);
	SLErase(&s, 5);
	SLPrint(&s);
	//SLErase(&s, -0);
	//SLPrint(&s);

	SLDestory(&s);
}

//测试查找指定元素和修改pos位置的值
void test4()
{
	SL s;
	SLInit(&s);
	SLPushBack(&s, 1);
	SLPushBack(&s, 2);
	SLPushBack(&s, 3);
	SLPushBack(&s, 4);
	SLPrint(&s);

	int ret = SLFind(&s, -1);
	if (ret != -1)
	{
		printf("找到了,下标是: %d  顺序表位置是: %d ", ret, ret + 1);
	}
	else
	{
		printf("没找到!\n");
	}

	SLModif(&s, 1, -10);
	SLPrint(&s);
	SLModif(&s, -1, -10);
	SLPrint(&s);
}

int main()
{
	test4();
	return 0;
}

OK~! The sequence table of the two versions is completed~!

5. Problems with sequence tables

1. The time complexity of inserting or deleting in the middle or head of the sequence table is O(N)

2. When expanding the capacity, if there is a lot of data, the capacity will be expanded in different places, which will increase the space complexity~!

3. Regardless of whether it is a static or dynamic sequence table, space will be wasted. This is unavoidable~!

Regarding how to solve these problems, please look forward to the next issue: Linked List~! ! !

OK, that’s all for sharing this issue~! Good brothers, see you next time! ! !

Guess you like

Origin blog.csdn.net/m0_75256358/article/details/132912696