顺序表的实现【数据结构】

文章目录

  • 1.线性表
  • 2.顺序表
    • [2.1 概念及结构](#2.1 概念及结构)
  • 3.模拟实现
    • [3.1 准备工作](#3.1 准备工作)
    • [3.2 顺序表的初始化与销毁](#3.2 顺序表的初始化与销毁)
    • [3.3 顺序表的尾插](#3.3 顺序表的尾插)
    • [3.4 顺序表的尾删](#3.4 顺序表的尾删)
    • 3.5顺序表的打印
    • [3.6 顺序表的头插](#3.6 顺序表的头插)
    • [3.7 顺序表的头删](#3.7 顺序表的头删)
    • [3.8 顺序表查找](#3.8 顺序表查找)
    • [3.9 顺序表在pos位置插入x](#3.9 顺序表在pos位置插入x)
    • [3.10 顺序表删除pos位置的值](#3.10 顺序表删除pos位置的值)
  • 4.代码整合

1.线性表

线性表(linear list)是n个具有相同特性的数据元素的有线序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表有:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就是说是连续的一条线。但是在物理结构上并不一定是连续的,比如链表。

线性表在物理上存储时,通常以数组和链式结构的形式存储。

2.顺序表

2.1 概念及结构

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

顺序表一般可以分为静态顺序表和动态顺序表
静态顺序表

使用定长数组存储元素。

c 复制代码
#define MAX 7
typedef int Datatype;//为了适用不同类型的顺序表
typedef struct SeqList
{
	Daratype a[MAX];
	int sz;//有效数据个数
}SL;

动态顺序表

使用动态开辟的数组存储

c 复制代码
typedef int Datatype;//为了适用不同类型的顺序表
typedef struct SeqList
{
	Daratype* a;
	int sz;//有效数据个数
	int capacity;//存储空间大小
}SL;

3.模拟实现

静态顺序表只适合于确定知道要存储多少数据的场景下。在储存空间不确定的场景下,对于静态顺序表当MAX开大了就会造成浪费,当MAX开小了又不够。所以在实际的场景中基本都是使用动态顺序表,根据需要动态分配空间大小。

下面是模拟实现:

3.1 准备工作

定义一个结构体

c 复制代码
typedef int Datatype;//为了适用不同类型的顺序表
typedef struct SeqList
{
	Datatype* a;
	int sz;//有效数据个数
	int capacity;//存储空间大小
}SL;

3.2 顺序表的初始化与销毁

对于顺序表的初始化,我的话会先给顺序表开好3个空间的大小.
注意:一定要传地址。

c 复制代码
void InitSeqlist(SL* ps)
{
	ps->a = (Datatype*)malloc(sizeof(Datatype)*3);
	if(ps->a == NULL)//扩容失败,直接退出程序
	{
		perror("InitSeqlist");
		exit(-1);
	}
	ps->sz = 0;
	ps->capacity = 3;
}

销毁

销毁我们直接free就可以了,任何其他值赋0.

c 复制代码
void DestorySeqlist(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->sz = 0;
	ps->capacity = 0;	
}

3.3 顺序表的尾插

插入前我们一定要先检查一下ps是不是应该空指针。

检查完ps后,对于数据的插入会存在两种情况:

1.顺序表已满,需要扩容

2.顺序表未,满直接插入

因为后面的头插与在特定位置的数据插入都会用到检查顺序是否已满,满就扩容的功能,那么我们可以封装成应该函数。

c 复制代码
void SeqlistCapacity(SL* ps)
{
	if(ps->capacity == ps->sz)//满了
	{
		Datatype* tmp = (Datatype*)realloc(ps->a, sizeof(Datatype) * 2*ps->capacity);
		if(tmp == NULL)//开辟失败
		{
			perror("realloc");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
}



void PushBack(SL* ps,Datatype x)
{
	assert(ps);
	//检查空间是否已满
	SeqlistCapacity(ps);
	ps->a[ps->sz] = x;
	ps->sz+=1;
}

3.4 顺序表的尾删

删除前我们一定要先检查一下ps是不是应该空指针。

同时还要删除该顺序表中的数据也又两种情况:

1.顺序表中的数据已经删完了,无法再删。

2.顺序表中的数据足够删除。直接删

c 复制代码
void PopBack(SL* ps)
{
	assert(ps);
	if(ps->sz>0)
	{
		ps->sz-=1;
	}
}

3.5顺序表的打印

直接打印就好了

c 复制代码
void PrintSeqlist(SL* ps)
{
	for (int i = 0; i < ps->sz; ++i)
	{
		printf("%d ", ps->a[i]);
	}
}

3.6 顺序表的头插

只要是插入数据就需要检查空间是否已满。

然后头插需要移动数据,我们需要把所有的数据都相后移动一位

这样的话,覆盖的顺序就很重要了,如果从前向后覆盖话,有效数据就没了

这样的话2就被覆盖了。

这样就不会了,还是不明白的话多画图就可以搞懂了。

c 复制代码
void PushFront(SL* ps,Datatype x)
{
	assert(ps);
	SeqlistCapacity(ps);
	for(int i = ps->sz;i>=1;--i)
	{
		ps->a[i] = ps->a[i-1];
	}
	ps->a[0] = x;
	ps->sz += 1;
}

3.7 顺序表的头删

只要是删除就需要判断顺序表是否为空。

这个图我就不画了,大家可以画一画从前面开始覆盖和从后面开始覆盖的图。就会豁然开朗的。

c 复制代码
void PopFront(SL* ps)
{
	assert(ps);
	assert(ps->sz!=0);
	for(int i = 0;i<ps->sz-1;++i)
	{
		ps->a[i] = ps->a[i+1];
	}
	ps->sz -= 1; 
}

3.8 顺序表查找

遍历顺序表,没找到的话就返回-1

c 复制代码
int FindSeqlist(SL* ps,Datatype x)
{
	assert(ps);
	for(int i = 0;i<ps->sz;++i)
	{
		if(ps->a[i] == x)
			return i;
	}
	return -1;//没找到
}

3.9 顺序表在pos位置插入x

就是类似与头插,头插可以理解为在0位置前插入数据。

c 复制代码
void InsertSeqlist(SL* ps,int pos,Datatype x)
{
	assert(ps);
	assert(pos>=0&&pos<=ps->sz)
	SeqlistCapacity(ps);
	for(int i = ps->sz;i>=pos+1;--i)
	{
		ps->a[i] = ps->a[i-1];
	}
	ps->a[pos] = x;	
	ps->sz+=1;
}

3.10 顺序表删除pos位置的值

类似于头删

c 复制代码
void EraseSeqlist(SL* ps,int pos)
{
	assert(ps);
	assert(pos>=0&&pos<ps->sz)
	assert(ps->sz!=0);
	for(int i = pos;i<ps->sz-1;++i)
	{
		ps->a[i] = ps->a[i+1];
	}
	ps->sz -= 1;
}

4.代码整合

c 复制代码
//seqlist.h
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int Datatype;//为了适用不同类型的顺序表
typedef struct SeqList
{
	Datatype* a;
	int sz;//有效数据个数
	int capacity;//存储空间大小
}SL;


void InitSeqlist(SL* ps);

void DestorySeqlist(SL* ps);

void SeqlistCapacity(SL* ps);

void PopBack(SL* ps);

void PrintSeqlist(SL* ps);

void PushFront(SL* ps, Datatype x);

void PopFront(SL* ps);

int FindSeqlist(SL* ps, Datatype x);

void InsertSeqlist(SL* ps, int pos, Datatype x);

void EraseSeqlist(SL* ps, int pos);

void PushBack(SL* ps, Datatype x);
//seqlist.c
#include "seqlist.h"

void InitSeqlist(SL* ps)
{
	ps->a = (Datatype*)malloc(sizeof(Datatype) * 3);
	if (ps->a == NULL)//扩容失败,直接退出程序
	{
		perror("InitSeqlist");
		exit(-1);
	}
	ps->sz = 0;
	ps->capacity = 3;
}

void DestorySeqlist(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->sz = 0;
	ps->capacity = 0;
}

void PushBack(SL* ps, Datatype x)
{
	assert(ps);
	//检查空间是否已满
	SeqlistCapacity(ps);
	ps->a[ps->sz] = x;
	ps->sz += 1;
}

void SeqlistCapacity(SL* ps)
{
	if (ps->capacity == ps->sz)//满了
	{
		Datatype* tmp = (Datatype*)realloc(ps->a, sizeof(Datatype) * 2*ps->capacity);
		if (tmp == NULL)//开辟失败
		{
			perror("realloc");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
}

void PopBack(SL* ps)
{
	assert(ps);
	if (ps->sz > 0)
	{
		ps->sz -= 1;
	}
}


void PrintSeqlist(SL* ps)
{
	for (int i = 0; i < ps->sz; ++i)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

void PushFront(SL* ps, Datatype x)
{
	assert(ps);
	SeqlistCapacity(ps);
	for (int i = ps->sz; i >= 1; --i)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->sz += 1;
}

void PopFront(SL* ps)
{
	assert(ps);
	assert(ps->sz != 0);
	for (int i = 0; i < ps->sz - 1; ++i)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->sz -= 1;
}

int FindSeqlist(SL* ps, Datatype x)
{
	assert(ps);
	for (int i = 0; i < ps->sz; ++i)
	{
		if (ps->a[i] == x)
			return i;
	}
	return -1;//没找到
}

void InsertSeqlist(SL* ps, int pos, Datatype x)
{
	assert(ps);
	SeqlistCapacity(ps);
	for (int i = ps->sz; i >= pos + 1; --i)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[pos] = x;
	ps->sz += 1;
}

void EraseSeqlist(SL* ps, int pos)
{
	assert(ps);
	assert(ps->sz != 0);
	for (int i = pos; i < ps->sz - 1; ++i)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->sz -= 1;
}

//test.c
#include "seqlist.h"

int main()
{
	//测试
	/*SL sl;
	InitSeqlist(&sl);
	PushBack(&sl, 1);
	PushBack(&sl, 2);
	PushBack(&sl, 3);
	PushBack(&sl, 4);
	PushBack(&sl, 5);
	PushBack(&sl, 6);
	PrintSeqlist(&sl);

	PopBack(&sl);
	PopBack(&sl);
	PopBack(&sl);
	PopBack(&sl);
	PrintSeqlist(&sl);
	PopBack(&sl);
	PopBack(&sl);
	PopBack(&sl);
	PrintSeqlist(&sl);

	PushBack(&sl, 1);
	PushBack(&sl, 2);
	PushBack(&sl, 3);
	PushBack(&sl, 4);
	PushBack(&sl, 5);
	PushBack(&sl, 6);
	PushFront(&sl, 100);
	PushFront(&sl, 200);
	PrintSeqlist(&sl);
	InsertSeqlist(&sl, 0, 1000);
	PrintSeqlist(&sl);

	int pos = FindSeqlist(&sl, 100);
	PopFront(&sl);
	PopFront(&sl);
	PopFront(&sl);

	PopFront(&sl);
	PrintSeqlist(&sl);*/

	//printf("%d", pos);
	return 0;
}

相关推荐
QXH20000023 分钟前
数据结构—单链表
c语言·开发语言·数据结构
imaima66624 分钟前
数据结构----栈和队列
开发语言·数据结构
David猪大卫44 分钟前
数据结构修炼——顺序表和链表的区别与联系
c语言·数据结构·学习·算法·leetcode·链表·蓝桥杯
Iceberg_wWzZ1 小时前
数据结构(Day14)
linux·c语言·数据结构·算法
Beauty.5682 小时前
P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布
数据结构·c++·算法
爱棋笑谦2 小时前
二叉树计算
java·开发语言·数据结构·算法·华为od·面试
jimmy.hua2 小时前
C++刷怪笼(5)内存管理
开发语言·数据结构·c++
Freak嵌入式2 小时前
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
java·开发语言·数据结构·python·接口·抽象基类
MogulNemenis3 小时前
力扣春招100题——队列
数据结构·算法·leetcode
学java的小菜鸟啊3 小时前
第五章 网络编程 TCP/UDP/Socket
java·开发语言·网络·数据结构·网络协议·tcp/ip·udp