当前位置: 首页 > news >正文

链表的实现与介绍

——————————————本文旨在交流计算机知识,欢迎指正—————————————

首先,我们回顾一下上一期讲的顺序表:

        顺序表是一种物理结构上连续的,一整块连续空间的逻辑表,但是,试想一下,如果每次我们都是申请在一块整块空间里面的顺序表,但是我们并不知道堆空间里面我们malloc一块空间之后我们并不知道它的存储样式,假设我们申请了两段空间,但是这两块空间之间只有两个单位,但是我们要新存下四个单位的顺序表,那么这两个单位的空间显然装不下我们的顺序表,我们需要另外申请一块新的空间去存它,但是这些夹着的碎片化空间就会造成浪费,无法使用:

于是,我们这时候需要一种新的结构去存储,来避免这种空间浪费的情况,链式存储结构应运而生:

 这样,我们就能理论上节约内存了;

(PS: 事实上,由于操作系统的存在,我们存储的只是在虚拟内存上,而它真实的内存其实映射到我们的物理内存上并非是如此的,于是对于顺序表操作系统给我们分配的物理内存其实并非真正连续的,我们这里讨论的其实只是无操作系统下关于内存的合理化分配)

下面,我们来详细讲讲关于链表的知识:

        首先我们给出链表的图形化结构:

       

         我们的链表包含一个头节点,一个尾部节点和数个中间节点,头结点的前驱是空,尾节点的后继也是空,中间节点都拥有前驱与后继。关于每一个节点,我们将其分为两个部分:1、数据域 2、地址域;数据域存储   该节点应该存储的数值,地址域指向下一个地址,然后我们通过地址域来访问下一个值。

这样,我们就构成了一份链式存储结构;于是,下面我们来尝试写一下代码:

  • 首先,和顺序表一样,我们先来定义链表的节点结构:
  • #ifndef COMMON_H
    #define COMMON_H
    typedef int Element_t;
    // 1. 定义链表的节点结构
    typedef struct _node{Element_t val;//数据域struct _node *next;//存储下一个节点地址的地址域
    } node_t;#endif //COMMON_H

 第二步,我们来写链表头结点的定义及函数的定义(如果对这里有所不明白的地方请翻到我的上一篇文章查看.h文件与.c文件的关系):

#ifndef CHAIN_LIST_H
#define CHAIN_LIST_H
#include "common.h"// 2. 定义带头指针的链表头结构
typedef struct {node_t *header;int count;
} ChainList_t;// 3. 链表头放到数据区,放到全局变量
void initChainList(ChainList_t *table);void destroyChainList(ChainList_t *table);		// 销毁该链表的元素区域,头不管int insertChainListHeader(ChainList_t *table, Element_t val);//头插法int insertChainListPos(ChainList_t *table, int pos, Element_t val);//按位插入int deleteChainListElement(ChainList_t *table, Element_t val);//按值删除void showChainList(const ChainList_t *table);//显示链表
#endif //CHAIN_LIST_H

第三步,我们开始正式写函数啦:

        (一) 初始化函数

void initChainList(ChainList_t* table) {table->count = 0;//表头不计入元素个数table->header = NULL;//表头指向NULL
}

        (二) 销毁链表函数

void destroyChainList(ChainList_t *table) {// 创建虚拟头节点,方便统一处理所有节点node_t dummy;dummy.next = table->header;// 从虚拟头节点开始遍历链表node_t *p = &dummy;node_t *tmp;// 逐个释放链表中的所有节点while (p->next) {tmp = p->next;         // 保存当前要删除的节点p->next = tmp->next;   // 从链表中移除该节点free(tmp);             // 释放节点占用的内存--table->count;        // 更新链表节点计数}// 输出链表剩余节点数printf("LinkList have %d node!\n", table->count);// table->header = NULL;
}

        (三) 头插法

int insertChainListPos(ChainList_t* table, int pos, Element_t val) {node_t dummy;dummy.next = table->header;// 1. 判断边界值if (pos < 0 || pos > table->count) {printf("insert pos invalid!\n");return -1;}// 2. 找到pos - 1索引的节点首地址node_t *p = &dummy;int index = -1;while (index < pos - 1) {p = p->next;++index;}node_t *new_node = malloc(sizeof(node_t));new_node->val = val;new_node->next = p->next;p->next = new_node;++table->count;table->header = dummy.next;return 0;
}

         (四)、删除操作

int deleteLinkListElement(LinkList_t* table, Element_t val)
{node_t *p = &table->head;//引入辅助节点while (p->next!=NULL){if (p->next->val == val)break;//如果当前辅助节点存储的值val等于删除目标,退出循环p = p->next;//辅助节点不断向后遍历}if (p->next == NULL)//判断是否有该值{return -1;}node_t *tmp = p->next;p->next = tmp->next;free(tmp);table->count--;//记录链表节点减1return 0;
}

 (五)、展现函数

void showChainList(const ChainList_t* table) {node_t *p = table->header;printf("link list: %d\n", table->count);while (p) {//如果p存在printf("%d\t", p->val);p = p->next;}printf("\n");
}

(六)、 主函数(测试函数)

// 带头节点的单向链表测试
int test01() {LinkList_t* table = createLinkList();if (table == NULL) {return -1;}for (int i = 0; i < 10; ++i) {insertLinkListHeader(table, i + 100);}insertLinkListPos(table, 3, 300);showLinkList(table);printf("========================\n");deleteLinkListElement(table, 105);showLinkList(table);releaseLinkList(table);return 0;
}int main() {test01();return 0;
}

锵锵~到这里就要收尾啦!希望这篇文字对你有所帮助!

相关文章:

  • Xcode 16.2 版本 pod init 报错
  • 【Linux】使用1Panel 面板让服务器定时自动执行任务
  • C++ 设计模式 《爬虫围城危机:小明用代理模式自救》
  • Linux安装字体
  • 如何使用Qwen-VL 2.5进行图像分割
  • 企业级AI-DevOps工具链的构成及实现方案
  • 篮球杯软件赛国赛C/C++ 大学 B 组补题
  • FFmpeg:Windows系统小白安装及其使用
  • 浏览器隐私模式与正常模式的区别
  • FOUPK3云服务平台主体
  • Web 前端性能优化全景指南与实战策略
  • Rust 学习笔记:共享状态并发
  • 视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
  • GC1808:高性能音频ADC的卓越之选
  • goreplay
  • iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
  • Kafka主题运维全指南:从基础配置到故障处理
  • glb/gltf格式批量转换fbx/obj,材质贴图在,批量转换stl/dae等其他格式,无需一个个打开
  • 消息队列系统设计与实践全解析
  • 面试高频问题
  • 十堰网站优化价格/营销是什么意思
  • 东莞多语言网站建设/百度明星人气榜排名
  • 大型网站开发实例/河南关键词排名顾问
  • 网站建设推推蛙/沈阳seo
  • 网站教程网/seo免费资源大全
  • 公司自己做网站流程和备案/百度上做推广怎么做