本篇文章的代码大多使用无头结点的单链表

相关定义:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h> typedef int DataType;
typedef struct Linklist{
LDataType data;
struct Linklist *next;
}Linklist,*pLinklist;

相关函数的定义:

pLinklist BuyNewNode(LDataType data);  //创建一个数据域为data的新结点
void InitLinklist(pLinklist *pL);  //初始化单链表
void PushBackLinklist(pLinklist* pL,LDataType data);  //尾插
void PushFrontLinklist(pLinklist *pL,LDataType data);  //头插
void PopBackLinklist(pLinklist *pL);  //尾删
void PopFrontLinklist(pLinklist *pL);  //头删
void PrintLinklist(pLinklist pL);  //打印出链表
pLinklist FindLinklist(Linklist *pL,LDataType data);  //找到数据域为data的第一个结点
void InsertLinklist(pLinklist *pL,pLinklist p,LDataType data);  //指定位置插入
void RemoveLinklist(pLinklist *pL,LDataType data);  //删除第一个数据为data的结点
void RemoveAllLinklist(pLinklist *pL,LDataType data);  //删除数据为data的全部结点
int IsEmpty(pLinklist pL);  //判断单链表是否为空
void DestoryLinklist(pLinklist *pL);  //删除整个链表,释放内存

由上面可以看出,只要是涉及到头指针发生改变的,我们在函数中都是传入指向头指针的指针。就像我们在swap函数中要交换a和b的值,我们是传入地址,而现在我们要改变头指针的值,也必须要传入指向头指针的一个指针来进行相关的操作。

此处借鉴了c语言函数传递参数的问题

下面是对函数的展开,我会比较详细的分析一下函数实现:

0.动态生成新结点

pLinklist BuyNewNode(LDataType data){
  pLinklist NewNode = (pLinklist)malloc(sizeof(Linklist));
  if(pLinklist == NULL){
    printf("空间开辟失败");
    return NULL;
  }
  NewNode->data = data;
  NewNode->next = NULL;
  return NewNode;
}

1.初始化操作

void InitLinklist(pLinklist *pL){
  assert(pL != NULL);
  (*pL) = NULL;
}

2.尾插一个数据为data的结点

void PushBackLinklist(pLinklist *pL,LDataType data){
  assert(pL != NULL);  //大多数中都有这个,是为了防止使用空指针,书中经常会说,千万不要使用空指针,你应该有印象
  pLinklist NewNode = BuyNewNode(data);
  if(*pL == NULL){  //判断这个是否为空链表
    *pL = NewNode;
    return ;
  }
  pLinklist cur = *pL;
  while(cur->next != NULL){  //其实这里也可以用cur != NULL,但是上面已经把把空链表大情况写出来了,如果再这样写会重复,不会错,但是复杂一点点
    cur = cur->next;
  }
  cur->next = NewNode;
}

3.头插一个数据为data的结点

void PushFrontLinklist(pLinklsit *pL,LDataType data){
  assert(pL != NULL);
  pLinklist NewNode = BuyNewNode(data);
  if(*pL == NULL){
    *pL = NewNode;
    return ;  
  }
  NewNode->next = *pL;
  *pL = NewNode;
}

4.判断无头链表是否为空

int IsEmptyLinklist(pLinklist pL){
  //这里的pL是一个指向链表的指针,而不是一个指向链表指针的指针
  return (pL == NULL);
}

5.尾删

void PopBackLinklist(pLinklist *pL){
  assert(pL != NULL);
  if(IsEmptyLinklist(*pL)){
    //*pL是一个指向链表的指针
    printf("链表为空");
    return ;
  }
  //尾删需要找到前面那一个结点
  pLinklist cur = *pL;
  pLinklist pre;
  if(cur->next == NULL){
    *pL = NULL;
    free(cur);
    cur = NULL;
    return ;
  }
  while(cur->next){
    pre = cur;
    cur = cur->next;
  }
  pre->next = NULL;
  free(cur);
  cur = NULL;
}

6.头删

void PopFrontLinklist(pLinklist *pL){
  assert(pL != NULL);
  if(*pL == NULL){
    printf("链表为空");
    return ;
  }
  pLinklist p = *pL;
  *pL = p->next;
  free(p);
  p = NULL;
}

7.找到第一个数据为data的结点

pLinklist FindLinklist(pLinklist *pL,LDataType data){
  assert(pL != NULL);
  plinklist cur = *pL;
  while(cur != NULL){
    if(cur->data == data){
      return cur;
    }
    cur = cur->next;
  }
  return NULL;
}

8.在给出的结点之前插入一个数据为data的结点

void InsertLinklist(pLinklist *pL,pLinklist p,LDataType data){
  assert(pL != NULL);
  pLinklist NewNode = BuyNewNode(data);
  pLinklist cur = *pL;
  while(cur->next != p){
    cur = cur->next;
  }
  NewNode->next = cur->next;
  cur->next = NewNode;
}

9.删除第一个数据为data的结点

void RemoveLinklist(pLinklist *pL,LDataType data){
  assert(pL != NULL);
  pLinklist cur = FindLinklist(pL,data);
  if(cur == NULL){
    printf("没找到");
    return ;
  }
  if(cur == *pL){
    //刚好在第一个结点
    *pL = cur->next;
    free(cur);
    cur = NULL;
    return ;
  }
  pLinklist p = *pL;
  while(p->next != cur){
    p = p->next;
  }
  p->next = cur->next;
  free(cur);
  cur = NULL;
}

10.删除每一个数据都是data的结点

void RemoveAllLinklist(pLinklist *pL,LDataType data){

  assert(pL != NULL); //删除每一个数据域都是data的结点
  pLinklist cur = NULL;
  pLinklist p = *pL;  //pre保存要删除结点的前一个结点
  pLinklist pre = *pL;
  while(p){
    if (p->data == data && (*pL) == p){
    //第一个结点是
    pre = p;
    p = p->next;
    *pL = p;
    free(pre);
    pre = NULL;
  }
  else if(p->data == data){
    //后续结点是
    cur = p;
    p = p->next;
    pre->next = p;
    free(cur);
    cur = NULL;
  }
  else{
    //此结点不是
    pre = p;
    p = p->next;
    }
  }

}

11.打印出链表

void PrintLinklist(Linklist *pL){
pLinklist cur = pL; //打印链表
while(cur){
printf("%d--->",cur->data);
cur = cur->next;
}
printf("NULL\n");
}

12.摧毁链表

void DestoryLinklist(pLinklist *pL){
assert(pL != NULL); //摧毁链表
pLinklist cur = *pL;
pLinklist pre = NULL;
if (*pL == NULL){
printf("链表为空");
return ;
}
if (cur->next = NULL){
*pL = NULL;
free(cur);
cur = NULL;
return ;
}
while(cur){
pre = cur;
cur = cur->next;
free(pre);
pre = NULL;
}
}
  • 添加到短语集

     
    • 没有此单词集:中文(简体) -> 英语...

       
    • 创建新的单词集...
  • 拷贝

不带头结点的单链表(基于c语言)的更多相关文章

  1. java编写带头结点的单链表

    最近在牛客网上练习在线编程,希望自己坚持下去,每天都坚持下去练习,给自己一个沉淀,不多说了 我遇到了一个用java实现单链表的题目,就自己在做题中将单链表完善了一下,希望大家作为参考也熟悉一下,自己 ...

  2. C/C++中创建(带头结点、不带头结点的)单链表

    1.带头结点的单链表(推荐使用带头结点的单链表)(采用尾插法) 了解单链表中节点的构成 从上图可知,节点包含数据域和指针域,因此,在对节点进行定义时,我们可以如下简单形式地定义: /* 定义链表 */ ...

  3. 链表习题(2)-一个集合用带头结点的单链表L表示,编写算法删除其值最大的结点。

    /*一个集合用带头结点的单链表L表示,编写算法删除其值最大的结点.*/ /* 算法思想:使用pre,p,premax,max四个指针,pre和p进行比较,premax和max进行最后的删除操作 通过遍 ...

  4. 链表习题(1)-设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点

    /*设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点*/ /* 算法思想:设f(L,x)的功能是删除以L为首结点指针的单链表中所有值等于x的结点, 则显然有f(L->next,x)的 ...

  5. c语言实现--不带头结点的单链表操作

    1,不带头结点的单链表操作中,除了InitList(),GetElem(),ListInsert(),ListDelete()操作与带头结点的单链表有差别外,其它的操作基本上一样. 2,不带头结点单链 ...

  6. 有一个线性表,采用带头结点的单链表L来存储,设计一个算法将其逆置,且不能建立新节点,只能通过表中已有的节点的重新组合来完成。

    有一个线性表,采用带头结点的单链表L来存储,设计一个算法将其逆置,且不能建立新节点,只能通过表中已有的节点的重新组合来完成. 分析:线性表中关于逆序的问题,就是用建立链表的头插法.而本题要求不能建立新 ...

  7. 不带头结点的单链表------C语言实现

    File name:no_head_link.c Author:SimonKly Version:0.1 Date: 2017.5.20 Description:不带头节点的单链表 Funcion L ...

  8. 无头结点的单链表(C语言)

    1.单链表: 在顺序表中,用一组地址连续的存储单元来一次存放线性表的结点,因此结点的逻辑顺序与物理顺序是一致的.但链表却不同,链表是用一组任意的存储单元来存放 线性表的结点,这组存储单元可以是连续的, ...

  9. Python实现不带头结点的单链表

    1 # 创建一个节点类 2 class Node: 3 def __init__(self, item): 4 self.item = item 5 self.next = None 6 7 8 # ...

随机推荐

  1. 汉明码、海明校验码(Hamming Code)

    目录 基础知识 汉明码/海明校验码 计算 基础知识 码距:又叫海明距离,是在信息编码中,两个编码之间对应位上编码不同的位数.例如编码100110和010101,第1.2.5.6位都不相同,所以这两个编 ...

  2. 微服务如何聚合 API 文档?这波秀~

    今天这篇文章介绍一下微服务如何聚合Swagger实现接口文档管理. 文章目录如下: 为什么需要聚合? 微服务模块众多,如果不聚合文档,则访问每个服务的API文档都需要单独访问一个Swagger UI界 ...

  3. Large Sacle Distributed Deep Networks

    本文是谷歌发表在NeurIPS 2012上的一篇论文,主要讨论了在几万个CPU节点上训练大规模深度网络的问题,并提出了一个名为DistBelief的软件框架.在该框架下实现了两种大规模分布式训练算法: ...

  4. Vue 源码解读(3)—— 响应式原理

    前言 上一篇文章 Vue 源码解读(2)-- Vue 初始化过程 详细讲解了 Vue 的初始化过程,明白了 new Vue(options) 都做了什么,其中关于 数据响应式 的实现用一句话简单的带过 ...

  5. bash初始化文件详解

    目录 交互式(interactive)shell/非交互式(non-interactive)shell 如何启动一个交互式shell/非交互式shell 如何判断是否为交互式shell 登录式(log ...

  6. 快速搭建一套k8s集群环境

    参考官网 kubeadm是官方提供的快速搭建k8s集群的开源工具,对于非运维人员学习k8s,kubeadm方式安装相对更简单. kubeadm创建一个集群:https://kubernetes.io/ ...

  7. Vulhub-漏洞环境的搭建(详细版)

    安装Vulhub需要的基础环境 更新现有的软件 复制代码 1 2 sudo apt-get update sudo apt-get upgrade 安装Docker 复制代码 1 2 3 4 5 6 ...

  8. Smartbi报表产品靠易用性出圈,国内口碑第一的BI厂商

    有调查显示,在对用户最关注商业智能哪些方面的调查中发现超过19%的被调查者认为产品易用性非常重要.在商业智能继续火热的2021年,BI产品的易用性深受用户的关注,并成为了选择产品的第一考虑要素. 在注 ...

  9. shell脚本实现文件的自动上传以及下载 scp sftp lftp 还有expect命令

    转至: 最近需求要求定期从一个[定期更新的文件] 中解析员工信息 ,插入到数据库中. 按理来说很简单,  无非就是io流读文件,然后crud balalalala..... 其实不是的, 我我写的这个 ...

  10. Idea项目添加新文件后运行出现404问题

    今天在项目里添加了一个新的html文件,然后运行项目页面跳转出现了404问题,找不到页面,经过我的一番查找,我注意到了Idea项目下有一个target文件,然后上网搜了解到这个target文件是mav ...