前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >顺序表专题

顺序表专题

作者头像
waves浪游
发布2024-04-02 10:08:10
640
发布2024-04-02 10:08:10
举报
文章被收录于专栏:C语言讲解C语言讲解
1.1 什么是数据结构

数据结构是由“数据”和“结构”两词组合而来。

什么是数据?

常见的数值1、2、3、4…、教务系统里保存的用户信息(姓名、性别、年龄、学历等等)、网页里肉眼可以看到的信息(文字、图片、视频等等),这些都是数据。

什么是结构?

当我们想要大量使用同?类型的数据时,通过手动定义大量的独立的变量对于程序来说,可读性非常差,我们可以借助数组这样的数据结构将?量的数据组织在?起,结构也可以理解为组织数据的方式。

概念: 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在?种或多种特定关系的数据元素的集合。数据结构反映数据的内部构成,即数据由哪部分构成,以什么方式构成,以及数据元素之间呈现的结构。

总结: 1)能够存储数据(如顺序表、链表等结构) 2)存储的数据能够方便查找

1.2 为什么需要数据结构

程序中如果不对数据进行管理,可能会导致数据丢失、操作数据困难、野指针等情况。通过数据结构,能够有效将数据组织和管理在?起。按照我们的方式任意对数据进行增删改查等操作。

最基础的数据结构:数组。

【思考】有了数组,为什么还要学习其他的数据结构?

假定数组有10个空间,已经使用了5个,向数组中插入数据的步骤:

  1. 求数组的长度,求数组的有效数据个数
  2. 向下标为数据有效个数的位置插入数据(注意:这里是否要判断数组是否满了,满了还能继续插入吗)
  3. 假设数据量非常庞大,频繁的获取数组有效数据个数会影响程序执行效率。

结论: 最基础的数据结构能够提供的操作已经不能完全满足复杂算法实现。

2. 顺序表的概念及结构

线性表:

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是?种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构,也就说是连续的?条直线;但是在物理结构上并不?定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

顺序表:

逻辑结构是线性的、物理结构是连续的。

顺序表和数组的区别:

顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口。

3. 顺序表分类

  1. 静态顺序表

概念:使用定长数组存储元素

代码语言:javascript
复制
//静态顺序表

#define N 100

typedef int SLDataType;//顺序表中数组类型不一定是整型,如果要变为字符类型,就可以在这里直接改;如果不这样定义,就要在代码中改很多次

struct SeqList
{
	SLDataType a[N];//定长数组
	int size;//有效数据个数
};

静态顺序表缺陷:空间给少了不够?,给多了造成空间浪费

  1. 动态顺序表
代码语言:javascript
复制
//动态顺序表

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr;//存储数据的底层结构
	int capacity;//记录顺序表的空间大小
	int size;//记录顺序表当前有效的数据个数
}SL;

//typedef struct SeqList SL;

4. 实现动态顺序表

4.1 初始化
代码语言:javascript
复制
void SLInit(SL* ps)
{
	assert(ps);

	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
4.2 顺序表的尾部插入
代码语言:javascript
复制
void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = 0 == ps->capacity ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));

		if (NULL == tmp)
		{
			perror("realloc fail!");
			exit(1);
		}

		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

void SLPushBack(SL* ps, SLDataType x)
{
	//断言 -- 粗暴的解决方式
	//assert(ps != NULL);
	assert(ps);

	//if判断 -- 温柔的解决方式
	//if (NULL == ps)
	//{
	//	return;
	//}

	//空间不够,扩容
	SLCheckCapacity(ps);

	//空间足够,直接插入
	ps->arr[ps->size++] = x;
	//ps->size++;
}

注: 扩容的原则:成倍数的增加(1.5倍、2倍)

4.3 打印顺序表
代码语言:javascript
复制
void SLPrint(SL* ps)
{
	assert(ps);
	
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	printf("\n");
}
4.4 顺序表的头部插入
代码语言:javascript
复制
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);

	//判断是否扩容
	SLCheckCapacity(ps);

	//旧数据往后挪动一位
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}

	ps->arr[0] = x;
	ps->size++;
}
4.5 顺序表的尾部删除
代码语言:javascript
复制
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);

	//顺序表不为空
	ps->size--;
}
4.6 顺序表的头部删除
代码语言:javascript
复制
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	//不为空执行挪动操作
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}

	ps->size--;
}
4.7 指定位置之前插入数据
代码语言:javascript
复制
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);

	SLCheckCapacity(ps);

	//pos及之后的数据往后挪动一位,pos空出来
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}

	ps->arr[pos] = x;
	ps->size++;
}
4.8 删除指定位置数据
代码语言:javascript
复制
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}

	ps->size--;
}
4.9 在顺序表中查找x
代码语言:javascript
复制
int SLFind(SL* ps, SLDataType x)
{
	//加上断言对代码的健壮性更好
	assert(ps);

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

	return -1;
}
4.10 顺序表的销毁
代码语言:javascript
复制
void SLDestroy(SL* ps)
{
	assert(ps);

	free(ps->arr);
	ps->arr = NULL;

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

完整代码:

代码语言:javascript
复制
//SeqList.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

静态顺序表
//
//#define N 100
//
//typedef int SLDataType;
//
//struct SeqList
//{
//	SLDataType a[N];
//	int size;
//};



//动态顺序表

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr;//存储数据的底层结构
	int capacity;//记录顺序表的空间大小
	int size;//记录顺序表当前有效的数据个数
}SL;

//typedef struct SeqList SL;

//初始化和销毁
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);//保持接口一致性

//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDataType x);
void SLPushFront(SL* ps, SLDataType x);

//顺序表的头部/尾部删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//指定位置之前插入数据
//删除指定位置数据
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);

int SLFind(SL* ps, SLDataType x);
代码语言:javascript
复制
//SeqList.c

#include "SeqList.h"

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

	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}




void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = 0 == ps->capacity ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));

		if (NULL == tmp)
		{
			perror("realloc fail!");
			exit(1);
		}

		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

//顺序表的头部/尾部插入
void SLPushBack(SL* ps, SLDataType x)
{
	//断言 -- 粗暴的解决方式
	//assert(ps != NULL);
	assert(ps);

	//if判断 -- 温柔的解决方式
	//if (NULL == ps)
	//{
	//	return;
	//}

	//空间不够,扩容
	SLCheckCapacity(ps);

	//空间足够,直接插入
	ps->arr[ps->size++] = x;
	//ps->size++;
}


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

	//判断是否扩容
	SLCheckCapacity(ps);

	//旧数据往后挪动一位
	for (int i = ps->size; i > 0; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}

	ps->arr[0] = x;
	ps->size++;
}


//顺序表的头部/尾部删除
void SLPopBack(SL* ps)
{
	assert(ps);
	assert(ps->size);

	//顺序表不为空
	ps->size--;
}


void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);

	//不为空执行挪动操作
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}

	ps->size--;
}



//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);

	SLCheckCapacity(ps);

	//pos及之后的数据往后挪动一位,pos空出来
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}

	ps->arr[pos] = x;
	ps->size++;
}


//删除指定位置数据
void SLErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}

	ps->size--;
}


//在顺序表中查找x
int SLFind(SL* ps, SLDataType x)
{
	//加上断言对代码的健壮性更好
	assert(ps);

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

	return -1;
}


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

	free(ps->arr);
	ps->arr = NULL;

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



void SLPrint(SL* ps)
{
	assert(ps);
	
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	printf("\n");
}
代码语言:javascript
复制
//test.c

#include "SeqList.h"

void slTest01()
{
	SL sl;
	SLInit(&sl);

	//测试尾插
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPrint(&sl);
	//SLPushBack(&sl, 5);
	//SLPrint(&sl);

	//SLPushBack(NULL, 6);

	//头插
	//SLPushFront(&sl, 5);
	//SLPushFront(&sl, 6);
	//SLPushFront(&sl, 7);
	//SLPrint(&sl);

	//尾删
	//SLPopBack(&sl);
	//SLPopBack(&sl);
	//SLPopBack(&sl);
	//SLPopBack(&sl);
	//SLPrint(&sl);

	//头删
	//SLPopFront(&sl);
	//SLPopFront(&sl);
	//SLPopFront(&sl);
	//SLPopFront(&sl);
	//SLPrint(&sl);

	//指定位置插入
	//SLInsert(&sl, 0, 100);
	//SLPrint(&sl);
	//SLInsert(&sl, sl.size, 200);
	//SLPrint(&sl);

	//SLInsert(&sl, 100, 300);
	//SLPrint(&sl);

	//删除指定位置的数据
	//SLErase(&sl, 0);
	//SLPrint(&sl);
	//SLErase(&sl, sl.size - 1);
	//SLPrint(&sl);

	SLErase(&sl, 1);
	SLPrint(&sl);
}

void slTest02()
{
	SL sl;
	SLInit(&sl);

	//测试尾插
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPrint(&sl);

	//测试查找
	//int ret = SLFind(&sl, 3);
	int ret = SLFind(&sl, 30);

	if (ret < 0)
	{
		printf("数据不存在,查找失败!");
	}
	else
	{
		printf("数据找到了,在下标为%d位置\n", ret);
	}
}


int main()
{
	//slTest01();
	slTest02();

	return 0;
}
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-04-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.1 什么是数据结构
  • 1.2 为什么需要数据结构
  • 2. 顺序表的概念及结构
  • 3. 顺序表分类
  • 4. 实现动态顺序表
    • 4.1 初始化
      • 4.2 顺序表的尾部插入
        • 4.3 打印顺序表
          • 4.4 顺序表的头部插入
            • 4.5 顺序表的尾部删除
              • 4.6 顺序表的头部删除
                • 4.7 指定位置之前插入数据
                  • 4.8 删除指定位置数据
                    • 4.9 在顺序表中查找x
                      • 4.10 顺序表的销毁
                      相关产品与服务
                      对象存储
                      对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                      http://www.vxiaotou.com