线性表和顺序表

目录

1.线性表

2.顺序表

2.1概念及结构

2.2 接口实现

2.3 数组相关面试题

2.3.1. 原地移除数组中所有的元素val,要求时间复杂度为O(N),空间复杂度为O(1)

2.3.2. 删除排序数组中的重复项

2.3.3. 合并两个有序数组。


1.线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列

线性表是一种在实际中广泛使用的数据结构

常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。

但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

2.顺序表

2.1概念及结构

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。(要求:数据必须从第一个位置开始,连续存储在数组上完成数据的增删查改。

顺序表一般可以分为:

1. 静态顺序表:使用定长数组存储元素。

SeqList.h

#pragma once

#define N 200
typedef int SLDataType;

//静态顺序表
//问题:N太小不够用,N太大,浪费空间
struct SeqList
{
	SLDataType a[N];
	int size;
};

2. 动态顺序表:使用动态开辟的数组存储。

SeqList.h

#pragma once

#define N 200
typedef int SLDataType


//动态顺序表   空间不够则增容
typedef struct SeqList
{
	SLDataType* a;//指向动态数组的指针
	int size;//数据个数
	int capacity;//容量——空间大小
}SL;

2.2 接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。

静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

数据结构就是在内存中管理数据,管理数据也就是完成数据的增删查改

越界检查,第一下越界不会报错,free

越界不一定报错

系统对越界的检查,是设岗抽查

malloc空间一般会查得严一点

防御式代码写法

assert(ps !=NULL);

SeqList.h

函数的声明

#pragma once//防止头文件被重复包含

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

//#define N 200
//typedef int SLDataType;
//
//// 静态顺序表 -- N太小,可能不够用,N太大,可能浪费空间
//struct SeqList
//{
//	SLDataType a[N];
//	int size;
//};

typedef int SLDataType;

//动态顺序表
typedef struct SeqList
{
	SLDataType* a; // 指向动态数组指针
	int size;      // 有效数据个数
	int capacity;  // 容量-空间大小
}SL;

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

// 增删查改

//void SeqListInit(SL s);

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

//检查
void SLCheckCapacity(SL* ps);

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

// 查找
int SLFind(SL* ps, SLDataType x);

//修改
void SLModify(SL* ps, int pos, SLDataType x);

//O(1)
// 尾插
void SLPushBack(SL* ps, SLDataType x);
//尾删
void SLPopBack(SL* ps);

//O(N)
//头插
void SLPushFront(SL* ps, SLDataType x);
//头删
void SLPopFront(SL* ps);

// 顺序表在pos位置插入x
void SLInsert(SL* ps, int pos, SLDataType x);
// 顺序表删除pos位置的值
void SLErase(SL* ps, int pos);

SeqList.c

顺序表的定义

#define _CRT_SECURE_NO_WARNINGS 1

#include "SeqList.h"

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

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

//初始化
void SLInit(SL* ps)
{
	assert(ps !=
<think>嗯,用户现在想了解线性表顺序表的定义及区别,我得先回顾一下之前提供的引用内容。根据用户给的引用,线性表是n个数据元素的有限序列,逻辑上是线性结构,但物理存储可以是数组或链表。顺序表则是线性表的一种实现方式,使用数组存储,元素在内存中连续存放。 首先,我需要明确两者的定义。线性表是一个抽象的概念,包括顺序表链表等具体结构。而顺序表特指用数组实现的线性表,物理结构连续。用户可能混淆了这两者的层次关系,所以需要分开解释。 接着,区别部分。要对比逻辑结构、物理结构、操作效率、扩展性等方面。比如,顺序表由于连续存储,支持随机访问,时间复杂度O(1),但插入删除需要移动元素,效率低。而链表物理上不连续,插入删除高效,但访问需要遍历。 还要注意用户提到的引用中的代码示例,比如静态分配动态分配的顺序表实现。这可能需要在回答中提到顺序表的两种分配方式,以及它们的优缺点,比如静态分配大小固定,动态可以扩容。 用户可能存在的疑问是,为什么线性表在逻辑上连续但物理上不一定,这时候需要举例子,比如链表在逻辑上是连续的,但物理上是分散的。而顺序表在物理上也是连续的。 另外,用户之前的问题是关于哈希表,现在转向线性结构,可能需要联系不同数据结构的应用场景,比如顺序表适合查找多,插入删除少的场景,链表反之。 最后,确保回答结构清晰,分点列出定义区别,使用中文,正确应用LaTeX格式,比如时间复杂度用$O(1)$,代码块用适当的格式。同时生成的相关问题要围绕线性表顺序表,比如它们的操作实现、应用场景比较等。</think>### 线性表顺序表的定义及区别 --- #### **一、线性表的定义** 1. **抽象概念** - 线性表(Linear List)是$n$个**具有相同特性**的数据元素的**有限序列**,记为$(a_1, a_2, \dots, a_n)$,其中$n=0$时称为空表[^2][^3]。 - **逻辑结构**:线性结构,元素间是“一对一”的关系,表现为一条直线(逻辑上连续)。 - **物理结构**:不限定存储方式,既可以是连续的数组(顺序表),也可以是非连续的链式结构(链表)[^1][^3]。 2. **核心特征** - 元素类型相同,且存在**前驱后继关系**(首元素无前驱,末元素无后继)。 - 支持基本操作:插入、删除、查找、遍历等[^2][^3]。 --- #### **二、顺序表的定义** 1. **具体实现** - 顺序表线性表的**一种物理存储实现方式**,通过**数组**在内存中分配**连续**的存储空间,元素按逻辑顺序依次存放[^3][^4]。 - 例如:静态分配顺序表的C语言定义: ```c #define MaxSize 10 typedef struct { int data[MaxSize]; // 静态数组 int length; // 当前长度 } SqList; ``` 2. **核心特征** - **物理连续**:元素在内存中连续存储,支持通过下标直接访问(随机访问)。 - **预分配空间**:静态分配(固定大小)或动态分配(可扩容)[^4]。 --- #### **三、线性表顺序表的区别** | **对比维度** | **线性表** | **顺序表** | |--------------------|-----------------------------------|-----------------------------------| | **定义层级** | 抽象的逻辑结构(描述数据关系) | 具体的物理实现(描述数据存储方式) | | **物理存储** | 不限定(可以是顺序或链式) | 必须连续存储(数组实现) | | **操作效率** | 依赖具体实现(如链表插入快,顺序表访问快)| 插入/删除需移动元素$O(n)$,访问$O(1)$[^3] | | **扩展性** | 链表可动态扩展,顺序表需扩容 | 静态分配大小固定,动态分配可扩容[^4] | | **典型应用** | 通用线性数据场景(如栈、队列的底层实现) | 需高频随机访问的场景(如静态查找表) | --- #### **四、关键示例对比** 1. **插入操作** - **顺序表**:在第$i$个位置插入元素,需将后续元素后移,时间复杂度$O(n)$。 ```c void Insert(SqList &L, int i, int e) { for (int j = L.length; j >= i; j--) L.data[j] = L.data[j-1]; L.data[i-1] = e; L.length++; } ``` - **链表**:插入只需修改指针,时间复杂度$O(1)$(不涉及元素移动)。 2. **访问操作** - **顺序表**:直接通过下标访问,如`L.data[3]`,时间复杂度$O(1)$。 - **链表**:需从头节点遍历,时间复杂度$O(n)$[^3]。 --- #### **五、总结** - 线性表是**逻辑结构**,顺序表是**物理实现**。 - 顺序表的优势在随机访问,劣势在动态修改;链表的优势在灵活扩展,劣势在访问效率[^1][^3]。 --- ### 相关问题 1. 顺序表的动态扩容机制如何实现? 2. 链表与顺序表在内存利用率上有何差异? 3. 如何选择线性表的实现方式(顺序表 vs 链表)?
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hey pear!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值