顺序表与单链表
创始人
2024-04-03 04:53:31
0

顺序表与单链表

  • 一,顺序表
    • 1,顺序表的简单介绍
    • 2,相关函数接口的实现
      • (1)初始化顺序表
      • (2)销毁顺序表
      • (3)打印顺序表
      • (4)检查空间
      • (5)尾插
      • (6)尾删
      • (7)头插
      • (8)头删
      • (9)任意位置插入
      • (10)任意位置删除
      • (11)查找
  • 二,单链表
    • 1,单链表的简单介绍
    • 2,相关函数接口的实现
      • (1)创建一个结点
      • (2)销毁链表
      • (3)打印链表
      • (4)尾插
      • (5)尾删
      • (6)头插
      • (7)头删
      • (8)在pos位置之后插入结点
      • (9)删除pos后的结点
      • (10)查找
      • (11)在pos位置之前插入节点
      • (12)删除pos位置之前的结点

一,顺序表

1,顺序表的简单介绍

1,顺序表的实质就是数组,但要求数据必须是连续存放的。

2,顺序表的物理结构与逻辑结构是统一的,简单地说,就是逻辑上连续的两个数据,
他们在物理空间上也是连续的,也就是内存空间是连续的。

内存开辟如下图所示:
在这里插入图片描述
下面我们主要介绍一下动态的顺序表,因为静态的顺序表不太灵活,一旦开辟好空间就不太好调整。

#pragma once
#include
#include
#includetypedef int SLDateType;typedef struct SeqList
{SLDateType* a;int size;int capcity;
}SeqList;
//初始化顺序表
void SLInit(SeqList* ps);
//销毁顺序表
void SLDestory(SeqList* ps);
//打印顺序表
void SLPrint(SeqList* ps);
//检查空间
void SLCheckCapcity(SeqList* ps);
//尾插 尾删
void SLPushBack(SeqList* ps, SLDateType x);
void SLPopBack(SeqList* ps);
//头插 头删
void SLPushFront(SeqList* ps, SLDateType x);
void SLPopFront(SeqList* ps);
//任意位置插入 删除
void SLInsert(SeqList* ps, int pos, SLDateType x);
void SLErase(SeqList* ps, int pos);
//查找
int SLFind(SeqList* ps, SLDateType x, int begin);

2,相关函数接口的实现

(1)初始化顺序表

void SLInit(SeqList* ps)
{assert(ps);ps->a = NULL;ps->capcity = 0;ps->size = 0;
}

我在初始化的时候没有给顺序表开辟空间,当然你可以为其开辟一部分空间。
将其capcity赋值为0;
size(数据个数)赋值为0;

(2)销毁顺序表

void SLDestory(SeqList* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capcity = 0;ps->size = 0;
}

将开辟的空间释放掉。

(3)打印顺序表

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

(4)检查空间

我们在插入数据之前都要先判断一下表是否还有空间,以防越界错误。

void SLCheckCapcity(SeqList* ps)
{assert(ps);if (ps->size == ps->capcity){int newcapcity = ps->a == NULL ? 4 : 2 * ps->capcity;SLDateType* tmp = realloc(ps->a, newcapcity * sizeof(SLDateType));if (tmp == NULL){perror("malloc fail");exit(-1);}ps->a = tmp;ps->capcity = newcapcity;}
}

(5)尾插

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

插入之前先检查顺序表是否有多余空间。

(6)尾删

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

(7)头插

void SLPushFront(SeqList* ps, SLDateType x)
{assert(ps);SLCheckCapcity(ps);int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];end--;}ps->a[0] = x;ps->size++;
}

(8)头删

void SLPopFront(SeqList* ps)
{assert(ps);assert(ps->size > 0);int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;
}

(9)任意位置插入

void SLInsert(SeqList* ps, int pos, SLDateType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapcity(ps);int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;
}

我们发现任意位置的插入包括了头插与尾插,所以可以改变一下之前的代码

头插

void SLPushFront(SeqList* ps, SLDateType x)
{/*assert(ps);SLCheckCapcity(ps);int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];end--;}ps->a[0] = x;ps->size++;*/SLInsert(ps, 0, x);
}

尾插

void SLPushBack(SeqList* ps, SLDateType x)
{/*assert(ps);SLCheckCapcity(ps);ps->a[ps->size] = x;ps->size++;*/SLInsert(ps, ps->size, x);
}

(10)任意位置删除

void SLErase(SeqList* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);assert(ps->size > 0);int begin = pos + 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;
}

同样之前头删,尾删的代码就可以更改:

头删

void SLPopFront(SeqList* ps)
{/*assert(ps);assert(ps->size > 0);int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;*/SLErase(ps, 0);
}

尾删

void SLPopBack(SeqList* ps)
{/*assert(ps);assert(ps->size > 0);ps->size--;*/SLErase(ps, ps->size - 1);
}

(11)查找

int SLFind(SeqList* ps, SLDateType x, int begin)
{assert(ps);assert(begin >= 0);for (int i = begin; i < ps->size; i++){if (ps->a[i] == x){return i;}}return -1;
}

二,单链表

1,单链表的简单介绍

链表与上述的顺序表有3个巨大的不同:
1,链表的逻辑结构与物理结构不统一(相邻数据的内存空间并不连续)
2,不存在空间满了的情况,插入新的数据就新开辟一个结点连接到链表上
3,插入删除数据不用数据,只是改变结点的连接方式即可

一般我们通常这样理解:
在这里插入图片描述
但实际的结构是这样的:
在这里插入图片描述
上一个结点的指针域存放着下一结点的地址,在内存中是上图那样存储的。

typedef int SLTDateType;typedef struct SListNode
{SLTDateType data;struct SListNode* next;
}SListNode;
//创建一个结点
SListNode* BuySListNode(SLTDateType x);
//打印链表
void SLTPrint(SListNode* phead);
//销毁链表
void SLTDestory(SListNode** pphead);
//尾插 尾删
void SLTPushBack(SListNode** pphead, SLTDateType x);
void SLTPopBack(SListNode** pphead);
//头插 头删
void SLTPushFront(SListNode** pphead, SLTDateType x);
void SLTPopFront(SListNode** pphead);
//查找
SListNode* SLTFind(SListNode* phead, SLTDateType x);void SLTInsertAfter(SListNode* pos, SLTDateType x);
void SLTEraseAfter(SListNode* pos);void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x);
void SLTErase(SListNode** pphead, SListNode* pos);

2,相关函数接口的实现

(1)创建一个结点

SListNode* BuySListNode(SLTDateType x)
{SListNode* newnode = (SListNode*)malloc(sizeof(SListNode));if (newnode == NULL){perror("malloc fail");exit(-1);}newnode->data = x;newnode->next = NULL;return newnode;
}

(2)销毁链表

void SLTDestory(SListNode** pphead)
{assert(*pphead);SListNode* cur = *pphead;SListNode* next = NULL;while (cur){next = cur->next;free(cur);cur = next;}*pphead = NULL;
}

(3)打印链表

void SLTPrint(SListNode* phead)
{SListNode* cur = phead;while (phead){printf("%d->", cur->data);cur = cur->next;}printf("NULL");
}

(4)尾插

void SLTPushBack(SListNode** pphead, SLTDateType x)
{SListNode* newnode = BuySListNode(x);if (*pphead == NULL){*pphead = newnode;}else{SListNode* ptail = *pphead;while (ptail->next){ptail = ptail->next;}ptail->next = newnode;}
}

(5)尾删

void SLTPopBack(SListNode** pphead)
{assert(*pphead);if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else{SListNode* cur = *pphead;while (cur->next->next){cur = cur->next;}cur->next = NULL;}
}

(6)头插

void SLTPushFront(SListNode** pphead, SLTDateType x)
{SListNode* newnode = BuySListNode(x);newnode->next = (*pphead)->next;*pphead = newnode;
}

(7)头删

void SLTPopFront(SListNode** pphead)
{assert(*pphead);SListNode* next = (*pphead)->next;free(*pphead);*pphead = next;
}

(8)在pos位置之后插入结点

void SLTInsertAfter(SListNode* pos, SLTDateType x)
{assert(pos);SListNode* newnode = BuySListNode(x);newnode->next = pos->next;pos->next = newnode;
}

(9)删除pos后的结点

void SLTEraseAfter(SListNode* pos)
{assert(pos);if (pos->next != NULL){SListNode* next = pos->next->next;free(pos->next);pos->next = next;}
}

(10)查找

SListNode* SLTFind(SListNode* phead, SLTDateType x)
{SListNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

(11)在pos位置之前插入节点

void SLTInsert(SListNode** pphead, SListNode* pos, SLTDateType x)
{SListNode* newnode = BuySListNode(x);if (pos == *pphead){newnode->next = (*pphead)->next;*pphead = newnode;}else{assert(pos);SListNode* cur = *pphead;while (cur->next != pos){cur = cur->next;}newnode->next = pos;cur->next = newnode;}
}

(12)删除pos位置之前的结点

void SLTErase(SListNode** pphead, SListNode* pos)
{if (pos == *pphead){free(pos);*pphead = NULL;}else{SListNode* cur = *pphead;while (cur->next != pos){cur = cur->next;}SListNode* next = pos->next;free(pos);cur->next = next;}
}

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...