数据结构——单链表(小白入门第二天)
一、什么是单链表?
定义:每个结点 除了存放数据元素外,还要存储指向下一个节点的指针;
优点:不要求大片连续空间,改变容量方便;
缺点:不可随机存取,要耗费一定空间存放指针
局限性:无法逆向检索
二、用代码定义一个单链表
方法一:
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函数怎么用
数据结构——单链表(小白入门第二天)相关推荐
- php链表和联表的区别,PHP_浅谈PHP链表数据结构(单链表),链表:是一个有序的列表,但 - phpStudy...
浅谈PHP链表数据结构(单链表) 链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个 ...
- php mysql 链表_浅谈PHP链表数据结构(单链表)
链表:是一个有序的列表,但是它在内存中是分散存储的,使用链表可以解决类似约瑟夫问题,排序问题,搜索问题,广义表 单向链表,双向链表,环形链表 PHP的底层是C,当一个程序运行时,内存分成五个区(堆区, ...
- python 单链表是否有回路_(Python3)数据结构--单链表之判断链表是否有环
前言 有Python基础 有数据结构单链表基础,没接触过的可以看下面链接 https://blog.csdn.net/sf9898/article/details/104946291 原理和实现 有一 ...
- 数据结构 —— 单链表(超详细图解 接口函数实现)
系列文章目录 数据结构 -- 顺序表 数据结构 -- 单链表 数据结构 -- 双向链表 数据结构 -- 队列 数据结构 -- 栈 数据结构 -- 堆 数据结构 -- 二叉树 数据结构 -- 八大排序 ...
- 数据结构-单链表基本操作(C语言实现)
参考书:王道考研数据结构 (此贴为博主学习408的笔记,因博主也是学习者,个人总结如有错误欢迎指正.如有侵权请告知,马上删除致歉) 单链表定义 单链表是线性表的链式存储,通过一组任意的存储单元来存 ...
- 20175330 数据结构-单链表(选做)
要求 参见附件,补充MyList.java的内容,提交运行结果截图(全屏) 课下推送代码到码云 ``` public class MyList { public static void mai ...
- 数据结构——单链表的C++实现
数据结构--单链表的C++实现 \qquad单链表的创建.求长度.查找.插入和删除的C++实现. #include<iostream> using namespace std;//1.定义 ...
- C语言数据结构单链表链表
数据结构–单链表 学习了顺序表,我们发现顺序表在向里面存放数据的时候很麻烦,比如我们要使用头插法存放一个数据到顺序表的时候,我们要将整个表都向后挪一位,这个操作就让人很难受.那么有没有一种结构可以让我 ...
- 数据结构-单链表(C语言代码)
数据结构纯属新手,小白一枚,欢迎批评指正! 直接上代码OVO! 定义结构体 typedef struct Node {int data; //数据域struct Node* next; //指针域 } ...
最新文章
- 20145326蔡馨熤《信息安全系统设计基础》第1周学习总结
- 关于java中的不可变类(转)
- 2011年第二届蓝桥杯决赛 —— C语言本科 —— 第一题
- python 多进程 多核_go/node/python 多进程与多核cpu
- java角度_java中角度或弧度的计算 | 学步园
- php什么程度算学会,十天学会PHP - 序1,学会的标准是什么?(20180820-1)
- text文字垂直居中_CSS垂直居中,你会多少种写法?
- 【华为云技术分享】opensuse使用zypper安装软件
- 任何事情的发生必有其目的,并有助于我
- My97DatePicker 演示和文档
- 《Linux命令行与shell脚本编程大全 第3版》Shell脚本编程基础---36
- sftp本地上传和远程下载
- 归并排序java代码实现
- 【干货分享】迄今为止最好用的编程字体-支持中文正确显示:同时彻底解决eclipse中文注释缩进排版混乱问题
- 用 Python 进行 OCR 图像识别
- Python 获取当天零点时间戳
- 让华为P30运行如飞的,是这个叫方舟的……
- 微应用 qiankun 项目搭建
- 研究型论文_CICIDS2017 数据集中基于异常的入侵检测系统的机器学习基准测试(英文论文)
- 最新微信三级分销系统源码 分销商城搭建 含完整代码包和安装部署教程