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

对于表,图,栈,队列,树等数据结构,我们采用链式和顺序结构都可以实现。
而链表又分为很多种,这一次先介绍最基础的链表
因为链表的空间并不连续,所以我们无需像顺序表一样考虑到表的容量,实现起来也更为简单,同时,这次实现的链表是不带头的单向链表,因为没有头节点,也没有返回值,我们就需要直接对指针进行操作,传递参数时就需要传二级指针

数据结构
typedef struct ListNode
{DATATYPE data;struct ListNode* next;
}ListNode;
实现的接口
void ListPrint(ListNode* list);
//打印链表
void ListPushBack(ListNode** list, DATATYPE x);
//头删
void ListPushFront(ListNode** list, DATATYPE x);
//头插
void ListPopBack(ListNode** list);
//尾删
void ListPopFront(ListNode** list)
//头插
void ListInsert(ListNode** pos, DATATYPE x);
//指定位置插入
void ListErase(ListNode** pos);
//指定位置删除
void ListDestory(ListNode** list);
//销毁链表
ListNode* ListFind(ListNode** list, DATATYPE x);
//查找链表元素

打印链表

void ListPrint(ListNode* list)
{if (list == NULL){printf("表空\n");return;}ListNode* cur = list;while (cur){printf("%d ", cur->data);cur = cur->next;}printf("\n");
}

头插

void ListPushFront(ListNode** list, DATATYPE x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->data = x;newnode->next = NULL;newnode->next = *list;*list = newnode;
}

头插:即每次在表的头部插入,所以我们每次只需要将原头节点设为插入节点的next节点,然后再将这个插入的节点作为头节点即可
如图所示,当我们依次插入1,2,3,4时

尾插

void ListPushBack(ListNode** list, DATATYPE x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->data = x;newnode->next = NULL;if (*list == NULL){*list = newnode;}else{ListNode* tail = *list;while (tail->next){tail = tail->next;}tail->next = newnode;}
}

尾插:即我们常用的方式,实现方法是先找到链表的最后一个节点,然后将他的next节点设为插入的节点,再让插入的节点的下一个next节点为空即可

头删

void ListPopFront(ListNode** list)
{if (NULL == *list)return;ListNode* next = (*list)->next;free(*list);(*list) = next;}

头删:我们先用next指针来保存首部的下一个节点,然后再将首部删除,使之前的next指针成为新的首部,即可实现头删

尾插

void ListPopBack(ListNode** list)
{if (NULL == *list){printf("表空\n");return;}else if ((*list)->next == NULL){free(*list);*list = NULL;}else{ListNode* prev = NULL, * tail = *list;while (tail->next){prev = tail;tail = tail->next;}free(tail);if (prev)prev->next = NULL;}
}

尾删:尾删的实现要稍微比头删麻烦一些,因为我们的这个链表并不是双向的,所以当我们遍历到最后一个节点的时候无法访问上一个节点,我们就需要用一个prev来保存上一个节点的地址,当我们遍历到最后一个节点的时候,直接释放掉这个一个节点,然后让prev指针的下一个节点指向空即可实现

链表查找

ListNode* ListFind(ListNode** list, DATATYPE x)
{   ListNode* cur = *list;while (cur){if (cur->data == x){return cur;}else{cur = cur->next;}}return NULL;
}

遍历链表查找元素

在Pos位置插入

void ListInsert(ListNode** pos, DATATYPE x)
{if (NULL == (*pos))return;ListNode* cur = (ListNode*)malloc(sizeof(ListNode));cur->data = x;cur->next = (*pos)->next;(*pos)->next = cur;
}

在Pos位置插入:让插入的元素的next指向pos位置的next,然后再让pos的next指向这个元素即可

在Pos位置删除

void ListErase(ListNode** pos)
{if (NULL == (*pos) || NULL == (*pos)->next)return;ListNode* next = (*pos)->next;(*pos)->next = next->next;free(next);next = NULL;
}

在Pos位置删除:这里指的是删除pos位置的后一个元素,即让pos指针的next指向他原本的next的next,也就是pos指针往后两个的位置

销毁链表

void ListDestory(ListNode** list)
{ListNode* cur = *list;while (cur){ListNode* next = cur->next;free(cur);cur = next;}*list = NULL;
}

具体代码:
头文件:

#pragma once#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#define _CRT_SECURE_NO_WARNINGS
#define LISTSIZE 10typedef int DATATYPE;
typedef struct ListNode
{DATATYPE data;struct ListNode* next;
}ListNode;void ListPrint(ListNode* list);
void ListPushBack(ListNode** list, DATATYPE x);
void ListPushFront(ListNode** list, DATATYPE x);
void ListPopBack(ListNode** list);
void ListPopFront(ListNode** list);
void ListInsert(ListNode** pos, DATATYPE x);
void ListErase(ListNode** pos);
void ListDestory(ListNode** list);
ListNode* ListFind(ListNode** list, DATATYPE x);

函数实现文件:

#include "LinkList.h"void ListPrint(ListNode* list)
{if (list == NULL){printf("表空\n");return;}ListNode* cur = list;while (cur){printf("%d ", cur->data);cur = cur->next;}printf("\n");
}void ListPushBack(ListNode** list, DATATYPE x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->data = x;newnode->next = NULL;if (*list == NULL){*list = newnode;}else{ListNode* tail = *list;while (tail->next){tail = tail->next;}tail->next = newnode;}
}void ListPushFront(ListNode** list, DATATYPE x)
{ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));newnode->data = x;newnode->next = NULL;newnode->next = *list;*list = newnode;
}void ListPopBack(ListNode** list)
{if (NULL == *list){printf("表空\n");return;}else if ((*list)->next == NULL){free(*list);*list = NULL;}else{ListNode* prev = NULL, * tail = *list;while (tail->next){prev = tail;tail = tail->next;}free(tail);if (prev)prev->next = NULL;}
}void ListPopFront(ListNode** list)
{if (NULL == *list)return;ListNode* next = (*list)->next;free(*list);(*list) = next;}ListNode* ListFind(ListNode** list, DATATYPE x)
{   ListNode* cur = *list;while (cur){if (cur->data == x){return cur;}else{cur = cur->next;}}return NULL;
}void ListDestory(ListNode** list)
{ListNode* cur = *list;while (cur){ListNode* next = cur->next;free(cur);cur = next;}*list = NULL;
}void ListInsert(ListNode** pos, DATATYPE x)
{if (NULL == (*pos))return;ListNode* cur = (ListNode*)malloc(sizeof(ListNode));cur->data = x;cur->next = (*pos)->next;(*pos)->next = cur;
}void ListErase(ListNode** pos)
{if (NULL == (*pos) || NULL == (*pos)->next)return;ListNode* next = (*pos)->next;(*pos)->next = next->next;free(next);next = NULL;
}

数据结构与算法 | 链表相关推荐

  1. JavaScript数据结构与算法——链表详解(下)

    在JavaScript数据结构与算法--链表详解(上)中,我们探讨了一下链表的定义.实现原理以及单链表的实现.接下来我们进一步了解一下链表的其他内容. 1.双向链表 双向链表实现原理图: 与单向链表不 ...

  2. JavaScript数据结构与算法——链表详解(上)

    注:与之前JavaScript数据结构与算法系列博客不同的是,从这篇开始,此系列博客采用es6语法编写,这样在学数据结构的同时还能对ECMAScript6有进一步的认识,如需先了解es6语法请浏览ht ...

  3. 数据结构与算法--链表实现以及应用

    数据结构与算法–链表实现以及应用 链表是面试时候使用最频繁的一种数据结构.链表的结构简单,他由指针将若干个节点链接成链状结构.链表的创建,插入,删除,查询操作都只有几行代码可以完成,代码量比较少,可以 ...

  4. 数据结构与算法-链表学习笔记

    数据结构与算法-链表学习笔记 链表的概念 链表是有序的列表. 链表是以节点的方式来存储,是链式存储,它在内存中并不是一定是连续的. 每个节点包含 data 域:存储数据, next 域:指向下一个节点 ...

  5. 数据结构与算法 -- 链表

    一.链表介绍 1.链表有地址不连续的结点序列,必须通过指针相互连接. 2.链表的分类: (1)单向线性链表 每个节点中除了存储数据结构内容以外,还需要保存指向下一个节点的指针,叫做后指针.最后一个节点 ...

  6. 数据结构与算法 —— 链表linked list(01)

    链表(维基百科) 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer).由于不必须按顺序存储, ...

  7. 数据结构与算法-链表篇

    链表与数组不同,是在物理空间中非连续的,依靠前一个节点记录下一个节点的地址进行连接的一种数据结构. 链表中每个节点存储的内容为当前节点和下个节点的指针. 链表一般分为三种 1.单向链表 2.双向链表 ...

  8. 数据结构和算法-链表

    链表分类 单向链表 双向链表 优势: 删除某个节点更加高效, 可以快速找到前驱节点 可以方便的在某个节点前插入元素 循环链表 当要处理的数据具有环形结构的时候, 适合循环链表. 如约瑟夫环问题 双向循 ...

  9. 数据结构与算法-链表

    在讲述链表之前让我们对数据结构进行一个简单的回顾:我们知道,数据结构指的是描述实际问题中各个数据项节点之间的前后逻辑结构关系,即要么是线性结构(即某一数据项的前继节点和后继节点有且只有一个)要么是非线 ...

最新文章

  1. 深度学习100例 - 卷积神经网络(CNN)实现车牌识别 | 第15天
  2. Elasticsearch系列「」学习路线
  3. 环路的产生及RIP防环机制
  4. Cloud for Customer ApplicationStarter.js和fQuickLogin
  5. 2017蓝桥杯省赛---java---A---7(正则问题)
  6. 分布式缓存管理与查询系统
  7. 关于64位win7环境下VS连接oracle数据库的问题
  8. elasticsearch同义词配置elasticsearch-analysis-dynamic-synonym
  9. c语言如何交替打印大小写字母,C/C++语言实现两个线程交替打印奇偶数
  10. Golang | Go 语言 编程练习 100题
  11. 2016年我的学习记录与搜索到的网站,将持续更新,主要介绍我在公司应用ecshop的学习记录...
  12. class类型重定义
  13. 树莓派 使用xbox360手柄
  14. 这行情我还老是管不住手,少kui点就偷着笑吧
  15. day2 编码与基本数据类型转换
  16. PPT基础(一)怎么把图片设置为背景
  17. 西方各国高职高专教育模式
  18. OriginPro绘图过程中遇到的问题及解决办法
  19. cocos2d-x-3.3-023-仿微信飞机大战-总体分析和建模
  20. Java中的门面设计模式

热门文章

  1. 封装案例-02-创建(qiang)类
  2. 单一职责原理讲解coding
  3. 方法重写(override)注意事项和使用细节
  4. linux svn配置教程,linux svn搭建及配置
  5. matlab复数方程的根,matlab解一元三次方程,得到的都是复数根。
  6. 【SpringBoot零基础案例01】【IEDA 2021.1】如何创建一个SpringBoot框架web项目
  7. 步步为营 .NET三层架构解析 四、Model设计(四种设计方式)
  8. ACM ICPC 2011-2012 Northeastern European Regional Contest(NEERC)G GCD Guessing Game
  9. Centos6.6安装之后调优
  10. Software develop Model