当前位置: 首页 > news >正文

408考研——单链表代码题常见套路总结

上期总结了顺序表,这其总结单链表,考虑到频繁使用指针,难度比顺序表略多一点。

一.定义和初始化

为了不让各位在一些写法方面的问题晕菜,先看这样一个例子:

typedef struct Student{int age;string name; 
}Stu,*Student1; Student *S1;
Student1 S2;

注意,上述的S1和S2均为Student类型的指针变量!也即*Student1直接用来声明的就是一个指针变量——即变量名之前不用加星号!换句话说,Student1只是出于某种考虑取的别名而已,参考鲁迅和周树人的区别。

再回到正文,我们定义的是一个单链表的节点,而并不是一个单链表——或者你也可以理解为一个只有一个节点的单链表~

typedef struct LinkNode{//定义一个单链表的节点类型 int data;LinkNode *next;
}LNode,*LinkList;

LNode只是LinkNode的简写,而*LinkList直接可以声明一个LinkNode的指针变量,效果上和*LinkNode一样,这么写是为了区别节点和单链表存在性质——类比马原中同一内容的不同表现形式。如下,两者均为LinkNode的指针类型变量。

LinkNode *L1;
LinkList L2;

另外还有一个初学者或者基础不牢固的人很容易犯晕的地方:既然声明的是LNode的指针变量,为什么不是LinkList*,而是*LinkList呢?实际上这里的*和指针变量没关系,* 是绑定到标识符而不是类型的。这里注意认得就行,不需要太深究为什么。

所以当我们执行下面的语句时,实际上是声明了一个指向头结点的指针,也即LinkNode*类型的变量,即便在我们看来似乎是声明了一个LinkList型的链表,这种写法使得语义较强。

LinkList L;

然后就是初始化,老套路还是引用传参:

void InitList(LinkList &L){L=(LNode*)malloc(sizeof(LNode));L->next=NULL;return;
}

博主用的是C++,记得引入头文件:

#include <cstdlib>

书上是上面的写法,实际上下面这种写法意思一样,只不过语义上更好——表达了"为链表分配内存"的意图,体现我们操作的是一个链表对象。当然各人有各自的习惯,看各位怎么用吧,这是小问题:

void InitList(LinkList &L){L=(LinkList)malloc(sizeof(LNode));L->next=NULL;return;
}

二.遍历和计算长度

首先实现两个常用操作,用于后续调用,首先是遍历单链表:

void PrintList(LinkList &L){LNode *p=L->next;//从头结点的后一位开始遍历while(p!=NULL){cout<<p->data<<" ";p=p->next;	} 
}

然后计算链表长度:

int CountLength(LinkList &L){int length=0;LNode *p=L;//注意,长度是要包含头结点的!while(p!=NULL){p=p->next;length++;} return length;
}

三.添加元素

本帖均使用带头节点的链表因此0号节点并不是存储数据的真正节点,1号开始才是。

void Insert(LinkList &L,int loc,int value){//注意,该链表带表头节点,所以在loc号位置插入,实际上是在有效节点的loc-1号位置插入 LNode *p=L;//指针p用来扫描,初始设置在表头int i=0;//while (p!=NULL&&i<=loc-2){//找到 loc-1号的前一个节点loc-2! p=p->next;i++;} if(p==NULL)return;LNode *s=(LNode*)malloc(sizeof(LNode));s->data=value;s->next=p->next;p->next=s;return; 	
}

然后测试一下,注意用于遍历的temp要指向头结点的下一个节点——即从真正的数据节点开始遍历,不然会额外输出一个很大的数——实际上就是链表的起始地址,这个地址每次编译都会重新分配一次~(测试的main函数见文末一起给出最终版本~)

这里博主给出打印了头结点的效果,没什么问题。此外这是头插法,如果是尾插法应该找到loc的后一个位置,在链表中即有效节点的loc位置,这里不过多赘述了~

四.删除元素

还是先找到Loc的前一个节点(即有效位置loc-1的前一个loc-2):

void DeleteByLoc(LinkList &L,int loc){int length=CountLength(L);if(loc>length-1||loc==0)return;//不能删除头结点,也不能删除范围外的位置	LNode *p=L;//删掉loc号节点即有效节点的loc-1号 int i=0;while (p!=NULL&&i<=loc-2){//同理,找到 loc-1号的前一个节点loc-2! p=p->next;i++;} LNode *q=p->next;p->next=q->next;free(q);return;
}

上一个例子里面的2号位置元素1被干掉了~

然后还可以按值删除,这里我们删掉第一个出现的value:

void DeleteByValue(LinkList &L,int value){LNode *p=L;LNode *q=p->next;while(q->data!=value&&q!=NULL){p=p->next;q=q->next;} //q是第一个value出现的位置,而p是前一个位置!p->next=q->next; free(q);
}

依旧没什么问题:

五.修改元素

由于不能随机访问,因此按位置修改也需要我们自己实现:

void AlterByLoc(LinkList &L,int loc,int value){int length=CountLength(L);if(loc>length-1||loc==0)return;//不能修改头结点,也不能修改范围外的位置	LNode *p=L;int i=0;while (p!=NULL&&i<=loc-1){//这和之前不同,要直接找到有效的i-1号节点 p=p->next;i++;} p->data=value; return;
}

以及按元素修改(修改第一个value值元素):

void AlterByValue(LinkList &L,int former,int value){LNode *p=L;while(p!=NULL&&p->data!=former)p=p->next;p->data=value;
} 

过于简单,最后一遍给出测试用例吧。

六.查询元素

同样由于失去了随机访问的特性,需要按位查找和按值查找:

int SearcheByValue(LinkList &L,int value){LNode *p=L; int i=0;//由于第一个头结点实际上是不存在的(非有效节点),因此从1开始统计 while(p!=NULL&&p->data!=value){p=p->next;i++;}return i;
}
int SearcheByLoc(LinkList &L,int loc){int length=CountLength(L);if(loc>length-1||loc==0)return;//不能查询头结点,也不能查询范围外的位置	LNode *p=L;int i=0;while(p!=NULL&&i<=loc-1)//loc号插入实际上就是有效节点的loc-1号(相当于头节点充当了数组的0号下标){p=p->next;i++;	} return p->data;
}

最后给出博主自己的测试用例,各位也可以自行编写:

int main(int argc, char** argv) {LinkList L;InitList(L);Insert(L,1,1);Insert(L,1,2);Insert(L,3,3);DeleteByLoc(L,2);DeleteByValue(L,2);AlterByLoc(L,1,100);AlterByValue(L,100,13);PrintList(L);cout<<endl;for(int j=1;j<=5;j++)Insert(L,1,j);PrintList(L);cout<<endl;cout<<SearcheByValue(L,13)<<endl;cout<<SearcheByLoc(L,3)<<endl;cout<<CountLength(L)<<endl;return 0;
}


文章转载自:

http://cOz1Em9T.fwjfh.cn
http://Pi8QJ0EB.fwjfh.cn
http://rGHmBwOF.fwjfh.cn
http://l2Vikvsm.fwjfh.cn
http://OvyLGI2d.fwjfh.cn
http://etvmAzO6.fwjfh.cn
http://EC10DxEc.fwjfh.cn
http://YVG81LbZ.fwjfh.cn
http://giMSHjvq.fwjfh.cn
http://MRyQhYL3.fwjfh.cn
http://BhLlO9Dz.fwjfh.cn
http://G1ZY1kIH.fwjfh.cn
http://gSGEVJsN.fwjfh.cn
http://nTDHDXca.fwjfh.cn
http://rGCQLtn7.fwjfh.cn
http://9XC7gjJJ.fwjfh.cn
http://Zqa9kDH4.fwjfh.cn
http://Cc55VlcI.fwjfh.cn
http://SUdNjCL6.fwjfh.cn
http://JRPd18ex.fwjfh.cn
http://Flj2FSy9.fwjfh.cn
http://6JWvGheT.fwjfh.cn
http://R8U9sEL0.fwjfh.cn
http://vWvcPENh.fwjfh.cn
http://p96Wrg61.fwjfh.cn
http://Mxeos0aN.fwjfh.cn
http://RYMUUHdP.fwjfh.cn
http://QdNgCUEz.fwjfh.cn
http://8Xi7ZoOE.fwjfh.cn
http://kXMiiA26.fwjfh.cn
http://www.dtcms.com/a/364968.html

相关文章:

  • [光学原理与应用-375]:ZEMAX - 分析 - 物理光学图
  • Debezium报错处理系列之第130篇:OutOfMemoryError: Java heap space
  • 复杂网络环境不用愁,声网IoT多通道传输实战经验丰富
  • 数据结构---双向链表
  • 明确用户提问的核心
  • 【计算机网络】TCP状态转移
  • AI随笔番外 · 猫猫狐狐的尾巴式技术分享
  • 醋酸铕:点亮现代生活的“隐形之光“
  • Java jar 如何防止被反编译?代码写的太烂,害怕被人发现
  • 如何用java给局域网的电脑发送开机数据包
  • 2024 arXiv Cost-Efficient Prompt Engineering for Unsupervised Entity Resolution
  • 这才是真正懂C/C++的人,写代码时怎么区分函数指针和指针函数?
  • Masonry
  • 少儿编程C++快速教程之——1. 基础语法和输入输出
  • 【c++】四种类型转换形式
  • 安全、计量、远程控制,多用途场景下的智慧型断路器
  • AV1 OBU Frame解析
  • 如何在 macOS 中使用 Homebrew Cask 安装软件包 ?
  • 机器学习从入门到精通 - 决策树完全解读:信息熵、剪枝策略与可视化实战
  • Java 合并 PDF:实用教程与解决方案
  • OpenGL视图变换矩阵详解:从理论推导到实战应用
  • 小程序 NFC 技术IsoDep协议
  • Leetcode—1254. 统计封闭岛屿的数目【中等】
  • 轻轻一个字母差别,就能把首屏时间砍半——为什么90%的人还不知道?
  • 游戏总监级“AI炼金术”!Firefly+NB创造不存在的神级材质
  • 小迪web自用笔记25
  • 【第三方软件项目验收中的安全漏洞(SQL注入/XSS)修复】
  • 彩笔运维勇闯机器学习--逻辑回归
  • Day20_【机器学习—逻辑回归 (1)—原理】
  • 浅谈人工智能之阿里云搭建coze平台