顺序表详解

一、顺序表定义

顺序表是用一段物理地址连续的存储单元存储数据元素的线性结构,一般采用数组存储。在数组上完成数据的增删查改(要求数据连续存储)。

二、顺序表的结构体

顺序表可以采用的两种方式,一种是静态结构,另一中动态结构(动态结构更优)。

2.1 静态顺序表

//静态顺序表

#define M 100

typedef int SLDateType;

typedef struct SeqList

{

        SLDateType data[N]; //定长数组

        int size; //有效数据长度

}SeqList;

2.2 动态顺序表

 //动态顺序表

typedef int SLDateType;

typedef struct SeqList

{

        SLDateType* data;//用数组存放数据

         int size;//实际大小

        int capacity;//空间大小

}SeqList;

三、功能实现

void SeqListInit(SeqList* ps);      //初始化顺序表
void SeqListDestroy(SeqList* ps);   //销毁顺序表

void SeqListPrint(SeqList* ps);     //打印顺序表
void SeqListPushBack(SeqList* ps, SLDateType x);  //尾插
void SeqListPushFront(SeqList* ps, SLDateType x);  //头插
void SeqListPopFront(SeqList* ps);  //头删 
void SeqListPopBack(SeqList* ps);   //尾删

// 顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* ps, int pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos);

3.1 顺序表初始化

首先得进行初始化,初始化时可以先给一定空间,空间满了会进行扩容,这里我们起初给的容量的是4。

//初始化顺序表
void SeqListInit(SeqList* ps)
{
	ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);
	if (ps->a==NULL)
	{
		perror("malloc");
		exit(-1);
	}
	ps->size = 0;
	ps->capacity = 4;
}

3.2 顺序表的扩容

每当顺序表容量满时(4个满),可以使用函数realloc来对顺序表进行扩容,每次增加4,这样动态开辟空间,就会减少空间的浪费,和避免空间不足问题。

//顺序表的扩容
void SLCheckCapacity(SeqList* ps)
{
	if (ps->size == ps->capacity)
	{
		SLDateType* tem = (SLDateType*)realloc(ps->a, ps->capacity * 2 * (sizeof(SLDateType)));
		if (tem == NULL)
		{
			perror("realloc");
			exit(-1);
		}
		ps->a = tem;
		ps->capacity *= 2;
	}
}

3.3 顺序表的打印

将顺序表节点的内容打印出来。

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

3.4 顺序表的插入

下面介绍三种顺序表的插入,让我们更好的理解顺序表的链接。

3.4.1 顺序表的头插

在顺序表的表头插入一个节点,将顺序表的所有节点从后往前依次后移,再将新节点插入到第一个节点位置。

void SeqListPushFront(SeqList* ps, SLDateType x)  //从后往前移动
{
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[0] = x;
	ps->size++;
}

3.4.2 顺序表的尾插法

尾插法需要先找到顺序表的尾部,然后再将新节点插入到尾部。

void SeqListPushBack(SeqList* ps, SLDateType x)
{
	SLCheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

3.4.3 在 pos位置插入元素

在指定位置插入元素,先找到pos的前一个结点,用来标记,然后插入pos,后面元素从后往前依次后移。

void SeqListInsert(SeqList* ps, int pos, SLDateType x)  //从后往前移动
{
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= pos-1)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos-1] = x;
	ps->size++;
}

3.5 顺序表的删除

顺序表的插入和删除是对应的,既然如此,我们对应插入写三个相对应的删除就比较的简单了。

3.5.1 顺序表的头删

删除第一个节点,并且将后面节点从前往后依次前移一位。

void SeqListPopFront(SeqList* ps)  //从前往后
{
	assert(ps->size);
	for (int i = 1; i < ps->size; i++)
	{
		ps->a[i - 1] = ps->a[i];
	}
	ps->size--;
}

3.5.2 顺序表的尾删

尾删很简单的一种就是,直接将长度减一,就可以达到尾删的目的。

void SeqListPopBack(SeqList* ps)
{
	assert(ps->size);
	ps->size--;
} 

3.5.3 删除pos位置元素

删除指定位置的元素,先找到pos位置,再将前一个元素依次从前往后覆盖上一个元素,达到删除的目的。

void SeqListErase(SeqList* ps, int pos)
{
	assert(ps->size);
	for (int i = pos-1; i < ps->size; i++)
	{
		ps->a[i] = ps ->a[i + 1];
	}
	ps->size--;
}

3.6 查找元素

查找元素,遍历一遍顺序表(数组),找到返回i+1(物理位置),没找到返回-1.

//在顺序表中查找
int SeqListFind(SeqList* ps, SLDateType x)
{
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i+1;
		}
	}
	return -1;
}

3.7 销毁顺序表

将顺序表空间释放,并且将顺序表指针制空,防止内存泄漏(好习惯)。

void SeqListDestroy(SeqList* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->size = ps->capacity = 0; 
}

四、结语

到这里顺序表的基本问题就解释完了,相信多多少少会解决大家心头的疑问,在数据结构的学习中应当善于思考,多画图,死磕代码,注意细节,将伪代码转换为代码,这样才能很好的掌握数据结构的有关知识,共勉,加油!!!

你可能感兴趣的:(数据结构,算法)