一、什么是单链表?

定义:每个结点 除了存放数据元素外,还要存储指向下一个节点的指针;

优点:不要求大片连续空间,改变容量方便;

缺点:不可随机存取,要耗费一定空间存放指针

局限性:无法逆向检索

二、用代码定义一个单链表

方法一:

struct LNode {ElemType data;//定义单链表节点类型  data变量用来存放数据元素(数据域)每个节点存放一个数据元素struct LNode* next;//定义指向下一个节点的指针(指针域) 指针指向下一个节点
};
struct LNode* p = (struct LNode*)malloc(sizeof(struct LNode));//增加一个新节点;再内存中申请一个节点所需空间,并用指针p指向这个结点

typedef<数据类型><别名>

typedef struct LNode LNode;
LNode* p = (LNode*)malloc(sizeof(LNode));

方法二:

struct LNode {ElemType data;struct LNode* next;
};//先定义数据类型typedef struct LNode LNode;//struct LNode 重命名为LNode
typedef struct LNode* LinkList;//用LinkList表示这个一个指向Struct LNode的指针

方法三:(方法二的简写)

typedef struct LNode{
ELemType data;
struct LNode* next;
}LNode, * LinList;

三、表示一个单链表

只需要声明一个头指针L,指向单链表的第一个结点

两种表达方式实质含义相同,强调重点不同 

四、初始化单链表

4.1不带头结点的单链表:

4.2带头结点的单链表:

L->next = NULL;( L这个指针指向的next指针域设置为NULL)

五、单链表的插入

5.1按位序插入(带头结点)

ListInsert(&L,i,e):插入操作;再表L的第i个位置上插入指定元素e,先找到i-1个结点

然后用malloc申请一个新结点,存入元素e,然后对指针进行修改

代码框架

typedef struct LNode
{ElemType data;  //数据域struct LNode *next; //指针域
}LNode,*LinkList;//定义结点bool ListInsert(LinkList &L,int i,ElemType e) /* 改变L */
{ /* 在L的第i个位置之前插入元素e */if(i<1)return false;//i从1开始LNode *p;int j=0;//第0个结点,指向头结点,实际从第一个开始;表示当前p指向第几个跌点p=L; //L指向头结点,头结点不存数据while(p!=NULL && j<i-1) /* 寻找第i-1个结点 */{p=p->next;j++;}/*i-1插入新结点*/if(p==NULL)return false;LNode *s;//新的结点s;s=(LinkList)malloc(sizeof(LNode)); /* 生成新结点 */s->data=e; /* 插入L中 */s->next=p->next;p->next=s; return true;
}

(55条消息) 王道2-06 单链表的插入 删除_黑糖儿*的博客-CSDN博客

代码实现

#include <stdio.h>
#include<stdlib.h>
typedef struct LNode{ //定义单链表结点类型 int data;  //数据域 struct LNode *next; //指针域 (为什么next指针域要定义为struct LNode呢,)
}LNode, *LinkList;//(为什么next指针域要定义为struct LNode呢?)
//next指针用来指向链表的下一个结点,该结点同样为一个LNode结构体,
//因此next要声明为指向LNode结构体的指针struct LNode*
bool InitList(LinkList &L)
{L = (LNode *)malloc(sizeof(LNode));if(L == NULL)return false;L->next = NULL;return true;
} //在第i个位置插入元素e(带头结点)
bool ListInsert(LinkList &L, int i, int e){  //判断i的合法性, i是位序号(从1开始)if(i<1)return false;LNode *p;       //指针p指向当前扫描到的结点 int j=0;        //当前p指向的是第几个结点p = L;          //L指向头结点,头结点是第0个结点(不存数据)//循环找到第i-1个结点while(p!=NULL && j<i-1){     //如果i>lengh, p最后会等于NULL  寻找第i-1个结点p = p->next;             //p指向下一个结点j++;}if (p==NULL)                 //i值不合法return false;//在第i-1个结点后插入新结点LNode *s = (LNode *)malloc(sizeof(LNode)); //申请一个结点s->data = e;  s->next = p->next;p->next = s;                 //将结点s连到p后,后两步千万不能颠倒qwqreturn true;
}void test()
{LinkList L;if(InitList(L))printf("true");printf("\n");ListInsert(L,1,3);ListInsert(L,2,5);LNode *s = L->next;while(s){printf("%d ",s->data);s = s->next;}return;
}int main(void)
{test();return 0;
}

(55条消息) 【数据结构】单链表按位序插入(带头节点)_向前的诚_的博客-CSDN博客_按位序插入

s->data = e;//将结点s的data值设置为e

s->next = p->next;//链表指针赋值,将p的下一个节点位置赋给s的下一个结点

p->next = s;//将结点s连接到p之后

平均复杂度O(n)

5.2按位序插入(不带头结点)

特殊处理:

if(i==1){LNode *s;//新的结点s;s=(LinkList)malloc(sizeof(LNode)); /* 生成新结点 */s->data=e; /* 插入L中 */s->next=L;//p->next就是头指针L=s; return true;}int j=1;//j从1开始

代码实现:

#include<stdio.h>
#include<stdlib.h>#define ElemType int
typedef struct LNode{  //定义单链表结点类型 ElemType data;     //每个结点存放一个数据元素 struct LNode* next; //指针指向下一个结点
}LNode,*LinkList;//初始化一个空白的单链表
bool InitList(LinkList &L)
{L=NULL;    //空表,暂时还没有存放任何结点(防止脏数据) return true;
}//在第i个位置插入元素e:
bool ListInsert(LinkList &L,int i,ElemType e)
{if(i<1)return false;if(i==1)   //插入第一个结点的操作与其他结点不同。 { LNode* s=(LNode*)malloc(sizeof(LNode));s->data=e;s->next=L;L=s;        //头指针指向新结点 return true;}LNode *p;      //指针p指向当前扫描到的结点 int j=1;       //当前p指向的是第几个结点 p=L;           //p指向第一个结点(不是头结点) while(p!=NULL&&j<i-1){p=p->next;j++;}if(p==NULL)return false;   //i值不合法 LNode* s=(LNode*)malloc(sizeof(LNode));s->data=e;s->next=p->next;p->next=s;return true;
}void OutputList(LinkList L)
{LinkList p=L;while(p){printf("%d ",p->data);p=p->next;}printf("\n");
}int main()
{   //声明一个指向单链表的指针 LinkList L;//初始化一个空表 InitList(L);//在单链表的第i个位置插入元素i: for(int i=1;i<=5;i++)ListInsert(L,i,i);//输出单链表中的所有元素: OutputList(L);return 0;
}

注意j最开始设置为1,表示p刚开始指向的结点是第一个结点

5.3指定结点的后插操作

InsertNextNode(LNode *p,ElemType e);

typedef struct LNode{int data;struct LNode *next;
}LNode, *LinkList;bool InsertNextNode(LNode *p, int e){if(p==NULL) return false;LNode *s = (LNode *)malloc(sizeof(LNode));if(s==NULL)            //内存分配失败return false;s->data = e;s->next = p->next;p->next = s;           //将结点s连到p之后return true;
}

(55条消息) 数据结构单链表:指定结点的前插、后插操作_挑灯夜未央的博客-CSDN博客_指定结点的前插操作

时间复杂度O(1)

直接调用InsertNextNode(p,e);

5.4 指定节点的前插操作

InsertPriorNode(LNode *p,ElemType e);

单链表只能往后找,不能往前面。

malloc——先申请一个结点s;

p->next = s——把新结点作为原来p结点的后置结点;

s->data = p->data——把p结点以前存放的数据元素复制到s结点;

p->data = e——把新插入的元素e放入原来p位置;

方法一:

typedef struct LNode{int data;struct LNode *next;
}LNode, *LinkList;//在p结点之前插入元素e
bool InsertPriorNode(LNode *p, int e){if(p==NULL) return false;LNode *s = (LNode *)malloc(sizeof(LNode));if(s==NULL)            //内存分配失败return false;s->next = p->next;      p->next = s;           //新结点s连到p之后s->data = p->data;     //将p中元素复制到s中p->data = e;           //p中元素覆盖为ereturn true;
}//核心思想:由于没法直接找到p结点的前结点,可以先把s结点插入p结点之后,
//再把p结点的数据复制到s结点,最后把p中数据赋值为新插入值e。

方法二:

时间复杂度O(1)

六、单链表的删除

6.1 按位序删除(带头结点)

ListDelete(&L,i,&e)——删除操作,删除表中L中第i个位置的元素,并用e返回删除元素的值

找到第i-1个结点,将其指针指向第i+1个结点,并释放第i个结点

//删除指定结点
bool DeleteNode(LNode *p){if(p==NULL)return false;LNode *q=p->next;  //令q指向*p的后继结点p->data=p->next->data;  //和后继结点交换数据域p->next=q->next;free(q);return true;
}//如果p结点是最后一个结点,则只能从表头开始依次寻找p的前驱 ,时间复杂度O(n)

①找到第i-1个结点

bool ListDelete(LinkList &L, int i, int e){  //判断i的合法性, i是位序号(从1开始)if(i<1)return false;LNode *p;       //指针p指向当前扫描到的结点 int j=0;        //当前p指向的是第几个结点p = L;          //L指向头结点,头结点是第0个结点(不存数据)//循环找到第i-1个结点while(p!=NULL && j<i-1){     //如果i>lengh, p最后会等于NULL  寻找第i-1个结点p = p->next;             //p指向下一个结点j++;}

②LNode *q = p->next;

定义指针q指向p结点的下一个,即第i结点

③e=q->data;

接下来q结点里的数据元素复制到e里面去(e是引用型,前面要加&)

④  p->next=q->next;

p的next指向q的next ,即NULL????????

⑤  free(q);

释放q的内存空间

最好时间度O(1)

最坏时间度O(n)

6.2 指定结点的删除

DeleteNode(LNode *p)

//删除指定结点
bool DeleteNode(LNode *p){if(p==NULL)return false;LNode *q=p->next;  //令q指向*p的后继结点p->data=p->next->data;  //和后继结点交换数据域p->next=q->next;free(q);return true;
}//如果p结点是最后一个结点,则只能从表头开始依次寻找p的前驱 ,时间复杂度O(n)

p->data=p->next->data——将p后继结点的数据复制到p的数据域里面

再让p结点的后继节点指向q的后继节点

释放归还q结点

七、单链表的查找

7.1 按位查找

GetElem(L,i)——获取表L中第i个位置的元素的值;

LNode * GetElem(LinkList L, int i){if (i<0){return NULL;}LNode *p;int j = 0;p=L;while (p!= NULL && j<i){p = p->next;j++;}return p;
}

在单链表的按位插入和删除中已经实现了第i-1个结点的查找

7.2 按值查找


LNode * LocateElem(LinkList L, int e){LNode *p = L->next;while (p != NULL && p->data != e){p = p->next;}return p;
}

①LNode *p = L->next——头指针p指向头结点的下一个结点

②while (p != NULL && p->data != e)——p≠NULL并且p的数据域≠e

p = p->next——满足条件让p指针指向下一个结点

平均时间复杂度O(n)

7.3 求表的长度

int Length(LinkList L){
int len=0;//统计表长
LNode *p=L;
while(p->next !=NULL){
p=p->next;
len++;
}
return len;
}

时间复杂度O(n)

八、单链表的建立

①初始化一个单链表

#include<stdio.h>
#include<stdlib.h>typedef struct LNode //定义单链表结点类型
{ElemType data;    //每个结点存放一个数据元素struct LNode *next; //指针指向下一个节点
}LNode,*LinkList;//初始化一个空的单链表(带头结点)
bool InitList(LinkList &L)
{L=(LNode*)malloc(sizeof(LNode)); //分配一个头节点if(L==NULL)return false;L->next=NULL;return true;
}void test()
{LinkList L; //声明一个指向单链表的指针//初始化一个空表InitList(L);
}

(55条消息) 单链表的初始化代码_啊哈哈哈哈大魔王的博客-CSDN博客_初始化单链表的代码

②每次取一个数据元素插入到表尾/表头

8.1 尾插法

位序插入

每次都要从头开始遍历,时间复杂度为O(n^2)

设置一个表尾指针r,每次就都从表尾插入


LinkList List_TailInsert(LinkList &L){int x;L = (LinkList ) malloc(sizeof (LNode));LNode *s,*r=L;scanf("%d", &x);//输入节点的值while (x!=9999){//输入9999表示结束(可为任意值)s=(LNode *) malloc(sizeof (LNode));s->data=x;r->next=s;r = s;scanf("%d", &x);}r->next =NULL;return L;
}

L = (LinkList ) malloc(sizeof (LNode))——malloc申请一个头结点,即初始化单链表的操作

LNode *s,*r=L——申明两个指针s,r都指向头结点

s=(LNode *) malloc(sizeof (LNode))——申请新结点,让s指向新结点
 s->data=x——把新结点的数值设为x(输入值)

r->next=s——把r的下一个指针指向s结点


r = s——让r指针指向s结点

........

8.2 头插法


LinkList List_HeadInsert(LinkList &L){//逆向建立单链表LNode *s;int x;L = (LinkList) malloc(sizeof (LNode));//创建头结点L->next = NULL;//初始为空链表scanf("%d", x);//输入结点值while (x!= 9999){//输入9999表示结束s=(LNode *) malloc(sizeof (LNode));//创建新结点s->data = x;s->next = L->next;L->next = s;//将新结点插入表中,L为头指针scanf("%d", x);}return L;
}

涉及其他知识点:

bool

返回值True or  False

(55条消息) C++中定义一个函数为bool类型的作用_&Mr.Gong的博客-CSDN博客_c++bool函数怎么用

数据结构——单链表(小白入门第二天)相关推荐

  1. php链表和联表的区别,PHP_浅谈PHP链表数据结构(单链表),链表:是一个有序的列表,但 - phpStudy...

    浅谈PHP链表数据结构(单链表) 链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个 ...

  2. php mysql 链表_浅谈PHP链表数据结构(单链表)

    链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个程序运行时,内存分成五个区(堆区, ...

  3. python 单链表是否有回路_(Python3)数据结构--单链表之判断链表是否有环

    前言 有Python基础 有数据结构单链表基础,没接触过的可以看下面链接 https://blog.csdn.net/sf9898/article/details/104946291 原理和实现 有一 ...

  4. 数据结构 —— 单链表(超详细图解 接口函数实现)

    系列文章目录 数据结构 -- 顺序表 数据结构 -- 单链表 数据结构 -- 双向链表 数据结构 -- 队列 数据结构 -- 栈 数据结构 -- 堆 数据结构 -- 二叉树 数据结构 -- 八大排序 ...

  5. 数据结构-单链表基本操作(C语言实现)

    参考书:王道考研数据结构 (此贴为博主学习408的笔记,因博主也是学习者,个人总结如有错误欢迎指正.如有侵权请告知,马上删除致歉)​​ 单链表定义 单链表是线性表的链式存储,通过一组任意的存储单元来存 ...

  6. 20175330 数据结构-单链表(选做)

    要求 参见附件,补充MyList.java的内容,提交运行结果截图(全屏) 课下推送代码到码云 ``` public class MyList {     public static void mai ...

  7. 数据结构——单链表的C++实现

    数据结构--单链表的C++实现 \qquad单链表的创建.求长度.查找.插入和删除的C++实现. #include<iostream> using namespace std;//1.定义 ...

  8. C语言数据结构单链表链表

    数据结构–单链表 学习了顺序表,我们发现顺序表在向里面存放数据的时候很麻烦,比如我们要使用头插法存放一个数据到顺序表的时候,我们要将整个表都向后挪一位,这个操作就让人很难受.那么有没有一种结构可以让我 ...

  9. 数据结构-单链表(C语言代码)

    数据结构纯属新手,小白一枚,欢迎批评指正! 直接上代码OVO! 定义结构体 typedef struct Node {int data; //数据域struct Node* next; //指针域 } ...

最新文章

  1. 20145326蔡馨熤《信息安全系统设计基础》第1周学习总结
  2. 关于java中的不可变类(转)
  3. 2011年第二届蓝桥杯决赛 —— C语言本科 —— 第一题
  4. python 多进程 多核_go/node/python 多进程与多核cpu
  5. java角度_java中角度或弧度的计算 | 学步园
  6. php什么程度算学会,十天学会PHP - 序1,学会的标准是什么?(20180820-1)
  7. text文字垂直居中_CSS垂直居中,你会多少种写法?
  8. 【华为云技术分享】opensuse使用zypper安装软件
  9. 任何事情的发生必有其目的,并有助于我
  10. My97DatePicker 演示和文档
  11. 《Linux命令行与shell脚本编程大全 第3版》Shell脚本编程基础---36
  12. sftp本地上传和远程下载
  13. 归并排序java代码实现
  14. 【干货分享】迄今为止最好用的编程字体-支持中文正确显示:同时彻底解决eclipse中文注释缩进排版混乱问题
  15. 用 Python 进行 OCR 图像识别
  16. Python 获取当天零点时间戳
  17. 让华为P30运行如飞的,是这个叫方舟的……
  18. 微应用 qiankun 项目搭建
  19. 研究型论文_CICIDS2017 数据集中基于异常的入侵检测系统的机器学习基准测试(英文论文)
  20. 最新微信三级分销系统源码 分销商城搭建 含完整代码包和安装部署教程

热门文章

  1. python通过xpinyin和pypinyin进行汉字转拼音
  2. python的质量控制模块_Python 代码的质量控制之 flake8 Pylint
  3. ioremap 与 mmap
  4. 机器学习python库--seaborn
  5. 深度学习(Deep Learning),自然语言处理(NLP)及其表达(Representation)
  6. TCP的可靠传输-停止等待协议
  7. 华为鸿蒙显示器,华为首次杀入显示器领域 劲爆新品为鸿蒙系统打头阵
  8. Unity仿微信QQ等聊天软件的UI效果
  9. 海报教程,制作楚乔传火焰海报
  10. 用指定的浏览器打开指定的网页(转)