2.顺序表_链表(附练习)

简介: 2.顺序表_链表(附练习)

1.线性表

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

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

2.顺序表

2.1概念及结构

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

顺序表一般可以分为:

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

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

主要来介绍一下动态顺序表

2.2 接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空 间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间 大小,所以下面我们实现动态顺序表。通过 typedef 来实现接口的引入

增强可读性(模拟接口):  结构体struct  def   SeqList

增强可修改性:                 类型(int)         def   SLDataType

一些增删查改的模拟实现:

typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{
  SLDataType* array;  // 指向动态开辟的数组
  size_t size;       // 有效数据个数
  size_t capicity;   // 容量空间的大小
}SeqList;
// 基本增删查改接口
void SeqListInit(SeqList* psl);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* psl);
// 顺序表尾插
void SeqListPushBack(SeqList* psl, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SeqList* psl);
// 顺序表头插
void SeqListPushFront(SeqList* psl, SLDataType x);
// 顺序表头删
void SeqListPopFront(SeqList* psl);
// 顺序表查找
int SeqListFind(SeqList* psl, SLDataType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* psl, size_t pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* psl, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* psl);
// 顺序表打印
void SeqListPrint(SeqList* psl);
}

一些典型的例题:  

27.移除元素--双指针法

26.删除相同元素

88.合并两个有序数组

2.3 顺序表的问题及思考

问题:

1. 中间/头部的插入删除,时间复杂度为O(N)

2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。

3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

补充:顺序表扩容的代码(是以size记数的    通过  :?来实现

/检查容量
void SLCheckCapacity(SL* ps)
{
  if (ps->size == ps->capacity)
  {
    int Newcapacity;
    Newcapacity = (ps->capacity == 0) ? 4 : (2 * ps->capacity);//扩容的实现
    SLDataType* p = (SLDataType*)realloc(ps->a, sizeof(SLDataType) * Newcapacity);
    if (p == NULL)
    {
      perror("realloc fail");
      exit(1);
    }
    else
    {
      ps->a = p;
      ps->capacity = Newcapacity;//realloc没错就将其赋值给ps->capacity
    }
  }
}

思考:如何解决以上问题呢?下面给出了链表的结构来看看。

3.链表

3.1 链表的概念及结构

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表 中的指针链接次序实现的 。

3.2 链表的分类

分为: 1.带头 2.单双向 3.循环   共八种

有许多的链表的结构,但是我们实际中最常用还是两种结构:

1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结 构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。//*next

2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都 是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带 来很多优势,实现反而简单了,后面我们代码实现了就知道了。//*prev *next

3.3 链表的实现

// 1、无头+单向+非循环链表增删查改实现
typedef int SLTDateType;
typedef struct SListNode
{
  SLTDateType data;
  struct SListNode* next;
}SListNode;
// 动态申请一个结点
SListNode* BuySListNode(SLTDateType x);
// 单链表打印
void SListPrint(SListNode* plist);
// 单链表尾插
void SListPushBack(SListNode** pplist, SLTDateType x);
// 单链表的头插
void SListPushFront(SListNode** pplist, SLTDateType x);
// 单链表的尾删
void SListPopBack(SListNode** pplist);
// 单链表头删
void SListPopFront(SListNode** pplist);
// 单链表查找
SListNode* SListFind(SListNode* plist, SLTDateType x);
…………

SListNode* SListFind(SListNode* plist, SLTDateType x);

// 单链表在pos位置之后插入x

// 分析思考为什么不在pos位置之前插入?

A: 简化插入操作的逻辑,避免处理头节点的特殊情况

以删除结点之后的代码为例:

// 删除pos之后的节点
void SLTEraseAfter(SLTNode * pos) {
  assert(pos);
  //pos->next不能为空
  assert(pos->next);
 
  SLTNode* del = pos->next;//将下一个位置取名为del
  pos->next = pos->next->next;//跳过改变指向
  free(del);//释放下一个位置
  del = NULL;
}


3.4 链表面试题

1. dummy新的头返回


2.pre cur  next 三指针法

3. 快慢指针 (二分类

3.5 双向链表的实现

//灵魂仍然是我们的增删查改~

以循环的尾插为例(第一个定为phead

代码实现:

void LTPushBack(LTNode* phead, LTDataType x)
{
    assert(phead);
    LTNode* new = creat(x);
    phead->pre->next =new;
    new->pre = phead->pre;
    new->next = phead;
    phead->pre = new;
}

4.顺序表和链表的区别

主机的存储要带电,本地磁盘可断电

暑假新增书单:《深入理解计算机系统》~


相关文章
|
1月前
|
存储
顺序表和链表(2)
【10月更文挑战第23天】
顺序表和链表(2)
|
1月前
|
存储 算法 数据管理
顺序表和链表(1)
【10月更文挑战第22天】
|
2月前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
28 3
|
6月前
|
存储 缓存 算法
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
数据结构和算法学习记录——总结顺序表和链表(双向带头循环链表)的优缺点、CPU高速缓存命中率
56 0
|
4月前
|
存储 算法
【初阶数据结构篇】顺序表和链表算法题
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
39 0
|
4月前
|
存储 缓存
【数据结构】——顺序表与链表
【数据结构】——顺序表与链表
|
6月前
|
存储 索引
顺序表和链表
通过以上示例,我们可以看到顺序表和链表在实际应用中如何操作。顺序表适合于需要频繁读取数据的场景,而链表则更适用于频繁修改数据的情况。在选择使用哪种数据结构时,应考虑到实际应用的需求和上下文环境。
43 2
|
6月前
|
存储 人工智能 测试技术
每日练习之排序——链表的合并;完全背包—— 兑换零钱
每日练习之排序——链表的合并;完全背包—— 兑换零钱
40 2
|
6月前
|
存储 算法
数据结构和算法学习记录——线性表之单链表(上)-初始单链表及其尾插函数(顺序表缺陷、单链表优点、链表打印)
数据结构和算法学习记录——线性表之单链表(上)-初始单链表及其尾插函数(顺序表缺陷、单链表优点、链表打印)
45 0
|
6月前
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表