前言

  以下代码来自于郝斌老师数据结构视频,加以自己的理解作了注释,用于学习和复习,欢迎指正错误。
  代码的运行环境:DEV-C++ 6.3版本,创建源文件为.cpp文件即可编译运行。

概念

  单链表又称线性表的链式存储,即通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表节点,除存放元素之神的信息外,还需要存放一个指向后继结点的指针。每个节点包含一个data和一个next指针。
          
  头指针:链表中第一个结点的存储位置叫做头指针,它指向头结点的数据域。头指针就是链表的身份和名字,是链表的必要元素。
  头结点:为了操作方便,在单链表的第一个结点之前插入一个结点,就是头结点。头结点的数据域可以不设任何信息,也可以存储链表的长度等。头结点的指针域指向链表的第一个元素结点。
  头结点的优点:1、由于第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个数据结点位置上的操作和和在其他位置上的操作一致。无需特殊处理。2、无论链表是否为空,其头指针都指向头结点的非空指针,(空表中头结点的指针域为空)因此空表和非空表的处理得到了统一。
  首结点:或称首元结点,单链表中第一个存放数据元素的结点。

#include <stdio.h>
#include <stdlib.h>typedef struct Node{int data;                                  //链表的数据域struct Node *pNext;                         //链表的指针域
}NODE,*PNODE;                                   //NODE等价于struct Node,PNODE等价于struct Node *PNODE creat_list(void);                           //创建链表
void traverse_list(PNODE pHead);                //遍历打印链表
bool is_empty(PNODE pHead);                     //判断链表是否空
int length_list(PNODE pHead);                   //返回链表长度
bool insert_list(PNODE pHead,int pos,int val);  //插入
bool delete_list(PNODE pHead,int pos,int *pVal);//删除
void sort_list(PNODE pHead);                    //链表排序int main(void){int len=0;int val;PNODE pHead = NULL;                        //等价于struct Node *pHead = NULLpHead = creat_list();                   //创建一个非循环单链表,将该链表的头结点的地址赋给pHeadtraverse_list(pHead);                 //遍历打印链表insert_list(pHead,4,12);traverse_list(pHead);                   //遍历打印链表    if(delete_list(pHead,4,&val)){printf("Delete successfully!\n");printf("The value is %d\n",val);}else{printf("Delete failed!\n");}traverse_list(pHead);//遍历
//  if(is_empty(pHead)){//      printf("The list is empty!\n");
//  }
//  len = length_list(pHead);
//  printf("%d\n",len);sort_list(pHead);traverse_list(pHead);//遍历
}
/*------------------------------
函数功能:尾插法创建单链表
参数为空
返回值为头结点地址
函数类型为PNODE
------------------------------*/
PNODE creat_list(void){int len;int i;int val;//临时存放用户输入的结点的值//分配了一个不存放有效数据的头结点/*-------------------------------头结点:第一个有效结点之前的结点,而第一个有效结点被称为首结点------------------------------*//*动态分配内存的函数开辟成功会返回开辟空间的地址,失败则返回NULL*/PNODE pHead = (PNODE)malloc(sizeof(NODE));if(NULL == pHead){                         //所以此处判断NULL是否成功分配内存printf("Memory allocation Failed!\n");exit(-1);}PNODE pTail = pHead;                     //pTail指向头结点和pHead一样pTail->pNext = NULL;                        //把pTail的指针域pNext清空,也就是指向尾结点printf("Please input the list number you want  to creat:\nlen= ");scanf("%d",&len);for(i=0;i<len;i++){printf("Please enter the value of %dth node:",i+1);scanf("%d",&val);PNODE pNew = (PNODE)malloc(sizeof(NODE));//创建pNew,临时结点if(NULL == pHead){printf("Memory allocation Failed!\n");exit(-1);}pNew->data = val;     //将用户数据赋给临时结点pNew的数据域pTail->pNext = pNew;   //pTail的指针域指向pNew,获取pNew的地址pNew->pNext = NULL;      //pNew的指针域清空,变成尾结点pTail = pNew;         //pTail变成尾结点/*这样的效果就是每次新加的结点pTail自动成为尾结点*/}return pHead;
}
/*------------------------------
函数功能:遍历链表
参数:pHead---接收链表的头结点地址
函数类型为PNODE
------------------------------*/
void traverse_list(PNODE pHead){//空链表仍然会有一个结点,就是头结点PNODE p = pHead->pNext;//头结点指向首结点,如果指向NULL,说明链表为空//p为NULL时,说明链表是空的,不为NULL时,就是有结点while(NULL != p){printf("%d ",p->data);p = p->pNext;//注意链表不是顺序存储,不可以用p++来遍历}printf("\n");return;
}
/*----------------------------------
函数功能:判断链表是否为空
参数:pHead---链表的头结点为空返回true,不为空的话返回false
-----------------------------------*/
bool is_empty(PNODE pHead){if(NULL == pHead->pNext){//如果为空的话,头结点的指针域指向尾结点的NULLreturn true;}else{return false;}
}
/*----------------------------------
函数功能:获得链表的长度并返回
参数:pHead---链表的头结点
-----------------------------------*/
int length_list(PNODE pHead){//创建一个p结点,令其指向头结点所指的结点,也就是首结点PNODE p = pHead->pNext;int len = 0;while(NULL!=p){++len;p=p->pNext;//移向后一个结点}return len;
}
/*----------------------------------
函数功能:向链表中插入数据
参数:pHead---链表的头结点pos---插入的位置val---插入的数据
-----------------------------------*/
bool insert_list(PNODE pHead,int pos,int val){//int val=0;int i=0;PNODE p=pHead;//首先判断链表是否为空以及插入位置是否合法//满足一个条件就返回false,终止程序if(i>pos-1||NULL==p->pNext){return false;}//让p移到插入结点的前一个结点while(NULL != p && i<pos-1){p=p->pNext;++i;}//一个新的临时结点,动态分配内存  PNODE pNew = (PNODE)malloc(sizeof(NODE));if(NULL == pNew){printf("动态内存分配失败!\n");exit(-1);}pNew->data = val;PNODE q=p->pNext;p->pNext = pNew;pNew->pNext = q;return true;
}
/*----------------------------------
函数功能:从链表中删除数据
参数:pHead---链表的头结点pos---删除数据的位置*pVal---返回删除的数据
-----------------------------------*/
bool delete_list(PNODE pHead,int pos,int *pVal){int i=0;PNODE p = pHead;//如果输入的位置不合法或者链表为空,返回falseif(i>pos-1||NULL==p->pNext){return false;}//如果p->pNext=NULL说明已经到链表尾结点,应该退出循环//i<pos-1,例如要删除第5个结点,i<4也就是循环到3退出//因为i是从0开始的,循环到3也就是循环了4次//两者中有一个不满足条件就会退出循环while(NULL!=p->pNext&&i<pos-1){p = p->pNext;++i;}//退出循环的p是第四结点PNODE q = p->pNext;//此时的q是第五个结点,因为p->pNext是第四个结点的指针域,它指向的是第五个结点*pVal = q->data;//将第五个结点的数据传出//删除p结点后面的结点//令第四个结点的指针域变成第五个结点的指针域//或者说原本第四结点指向第五结点,现在指向第六结点p->pNext = p->pNext->pNext;//第五结点变成了q,所以需要释放第五结点的内存//动态分配的内存必须使用free释放free(q);q=NULL;//断开q和该地址的联系return true;
}
/*----------------------------------
函数功能:对链表数据进行排序
参数:pHead---链表的头结点
-----------------------------------*/
void sort_list(PNODE pHead){int i,j,t;int len;len = length_list(pHead);PNODE p,q;for(i=0,p=pHead->pNext;i<len-1;i++,p=p->pNext){//p=pHead->pNext相当于对p初始化,使其指向该链表的首结点//p=p->pNext,其指针域指向下一个结点,每循环一次p都会更新为下一个结点for(j=i+1,q=p->pNext;j<len;j++,q=q->pNext){/*p->pNext是首结点后的第二结点,也就是q变成第二结点q=q->pNext自增到链表的尾结点,<len在len-1处停下来因为i是从0开始的,循环次数和链表结点个数对应即可类似于数组a[i]>a[j]*/if(p->data>q->data){  //a[i]>a[j]t = p->data;      //t = a[i]p->data = q->data;    //a[i] = a[j]q->data = t;      //a[j] = t }   }}
}

郝斌数据结构-线性表之单链表程序(C语言版)相关推荐

  1. 数据结构-线性表之单链表

    文章目录 一:相关概念 (1)什么是链表 (2)链表的优点和缺点 (3)链表的分类 二:实践 (1)准备工作 (2)结构体定义 (3)操作 A:创造头结点(初始化) ①:头结点?头指针? ②:初始化 ...

  2. [数据结构](线性表之单链表)

    文章目录

  3. 线性表11|单链表小结:腾讯面试题 - 数据结构和算法16

    线性表11|单链表小结:腾讯面试题 让编程改变世界 Change the world by program 静态链表的删除操作 我们的故事还没结束,小C看到小A和2B这样非法的勾当,内心觉得很不爽,一 ...

  4. C++线性表(单链表)的应用算法(附源码)

    C++线性表(单链表)的应用算法 线性表(单链表)的应用算法: 构造一个递增有序的正整数链表,实现链表分解为一个奇数表和一个偶数表,之后再将两个链表合并一个递减链表. 运行截图 代码实现 /* 线性表 ...

  5. 数据结构顺序表和单链表优缺点

    1:顺序表的优缺点:List 优点:顺序表示用地址连续的存储单元顺序存储线性表中的各个元素,逻辑上相领的数据元素在物理位置上也相领,因此,在顺序表中查找任何一个位置上的数据元素非常方便: 缺点:在顺序 ...

  6. 数据结构----顺序表与单链表(JAVA)

    下面为学习顺序表和单链表的一些基本操作函数: 1 public class SeqList<T> extends Object { 2 protected int n; 3 protect ...

  7. java单链表输出_数据结构基础------1.线性表之单链表的创建与输出方法(Java版)...

    基础知识: 线性表(linear list),是其组成元素间具有线性关系的一种线性结构. 线性表有 ①顺序存储结构(sequential storage structure) 顺序存储结构可以简单的理 ...

  8. 【数据结构:线性表】单链表

    在学习了顺序表,我们可能会对其有一些思考: 中间/头部的插入删除,时间复杂度为O(N) 增容需要申请新空间,拷贝数据,释放旧空间.会有不小的消耗. 增容一般是呈2倍的增长,势必会有一定的空间浪费.例如 ...

  9. 【数据结构】线性表之单链表

    目录 一.链表的概念 1.概念 2.分类 3.重点 二.单链表模拟实现 1.准备 2.头插法 3.尾插法 4.指定下标插入 5.遍历 6.删除第一次出现的元素key 7.删除所有的key 8.双指针删 ...

  10. 卜若的代码笔记-数据结构系列-第三章:链表-最简单的线性表:单链表

    1.一个最简单的线性表 1.1单链表的特征: a.链表无法通过索引获取链表元素,只能从头开始一个一个的后继去找. b.链表无法找到父节点 1.2结构: 1.3 实现 我们来讨论一下它的时间复杂度: 1 ...

最新文章

  1. Apache Commons包 StringUtils工具类深入整理(转载)
  2. Linux中etc目录详解
  3. android自定义滤镜,【Android】自定义View那点事(三)ColorFilter篇
  4. Java经典基础与高级面试36题和答案
  5. iphone短信尚未送达_iPhone开启这个功能,从此告别垃圾短信骚扰!
  6. 文件类的操作 File c# 1614823687
  7. 推荐Android中两个很好用的banner,可无限轮播,可使用第三方图片加载框架加载网络图...
  8. 华为交换机配置时区_把华为交换机设置成时钟源服务器(NTP)
  9. 探索FireMonkey的StyleBook皮肤控件的使用
  10. 淘宝商品爬虫实战笔记
  11. php mobi_PHP核心技术与最佳实践 mobi epub
  12. 一日一技:geopandas,用python画地图原来这么简单!
  13. 解决 Request Entity Too Large问题
  14. Hadoop题库(选择题、判断题)详细介绍
  15. 决策树--信息增益,信息增益比,Geni指数
  16. 控制工程中的数学建模(9)——音圈电机的原理及数学模型
  17. 探索Kubernetes HPA
  18. UVA 1626 括号序列
  19. (华师)CSMA技术的P—坚持算法规则是什么?
  20. python怎样创建列表_如何创建Python列表(list)和添加元素

热门文章

  1. Steam上传游戏包体的三种方法
  2. Windows中的iTunes Setup Assistant驱动程序错误修复
  3. linux日志分析步骤,Linux系统日志分析的基本教程
  4. AST2500用户添加自定义IPMI交互命令
  5. 清除Windows远程桌面连接记录
  6. 十折交叉验证python_Python机器学习:6.2 K折交叉验证评估模型性能
  7. vc中控件字体的设置(转)
  8. 值得收藏的UmiJS 教程
  9. 解决Deepin开机锁屏状态下能够使用触控板而解锁之后无法使用触控板的BUG
  10. VOC 2007数据集结构