单链表的应用(电话本)

单链表

单链表的定义就不说了, 很简单, 请自行百度; 那么从今天的主题<单链表的应用>入手; 利用单链表实现电话本的模拟程序:定义单链表的数据类型,将头插法和尾插法、插入、逆置、删除、查找、修改、计数、输出等操作都定义成子函数的形式,最后在主函数中调用它( 兄弟们调用就不弄了, 自行测试, 增加动手能力 )
整个程序最主要的步骤还是插入, 查找, 删除操作, 其他操作都可以围绕这三个操作来进行, 其实单链表无论是什么操作都可以总结为指针的操作, 无非是指针的指向, 通过指针的指向就能完成很多步骤, 但是在单链表中由于指针是单向的, 不像双链表那样可以双向操作, 所以操作起来有点不太方便(其实还是很简单的, 只是说了吓唬人的)
此处做注释: 链表的head节点数据域不存数据, head所在的位置是-1, 链表中元素是从0号开始
那么我就先从insert开始:

insert操作
void insert(int index,LNode *L1,LNode *L2);
insert就是在特定的位置(index)把L2节点连接到L1上面, 所以就有如下实现方式:

void insert(int index,LNode *L1,LNode *L2){for(int i=0;(i<index)&&(L1!=NULL)&&(L2!=NULL);i++,L1=L1->next);L2->next=L1->next;L1->next=L2;
} 

L1与L2需要判断是否为空(避免引用非法指针), 上面的for操作主要是将指针L1移动到需要插入的位置的前一个位置, 首先将L2的next指针存入原本L1的后一个位置的地址, 然后将L1的next指针存入L2的地址, 这两步操作不能颠倒, 颠倒, 原本链表中L1后面部分的链表结构将会丢失; (请细细理解)
在创建链表的过程中我们可以选择头插法或者尾插法进行创建链表;
所谓头插法简单的来说就是每次插入操作总是把插入节点的位置定位0号, 头插法的意义就在于我们可以很容易完成逆置的操作, 头插法代码如下:

void insertHead(LNode *L1,LNode *L2){insert(0,L1,L2);
}

头插法就是在0号位置把L2插入到L1的后面, 如果将头插法应用到创建链表, 那么此处的L1便是head

尾插法就是每次在尾部插入节点, 插入的位置总是末尾; 代码如下:

void insertTail(LNode *L1,LNode *L2,int t){insert(t,L1,L2);
}

此处L1, L2的含义与头插法中的含义一致, t表示末尾的位置, 末尾需要传入参数来确定, 待会在main函数中测试再进行说明, 两个插入的区别就在于位置的变化, 由两种插入方面所形成的链表顺序是相反的

逆置操作
上面提到逆置操作需要用到头插法, 因为每次节点传入的insertHead中, 我总是把节点插入到0号位置, 也就是head后面, 一个正序的链表, 我把它的节点按顺序不断拆下来, 同时将每个拆下来的节点连接到head的0号位上面, 而不是又按照原有的顺序进行顺序连接(表面上看好像连和没连一样, 这里你需要画图好好思考), 举个例子: head 0 1 2 3的顺序表, 0拆下连接到head上面, 1拆下连接到head上面, 此时0就连接到1号上面, 顺序为head 1 0, 同理, 2拆下连接到head上面, 1又连接到2上面, 顺序为head 2 1 0 ,最后整个过程重复, 得到的顺序就是head 3 2 1 0, 然后就可以做到把一个正序的链表变为逆序的
话不多说, 上代码:

void convert(LNode *L){//此处逆置是对整个链表逆置, L传入的是headLNode* p=L->next;L->next=NULL;LNode* q;int t_size=size;while(t_size>0){q=p->next;p->next=NULL;insert(0,L,p);p=q;t_size--;}
}

LNode* p=L->next;L->next=NULL;LNode* q;是将head分离, while内部的操作主要是通过不断迭代的方式, 做到将第一个节点与第二个节点进行分离, 以达到将在0号位插入的效果

删除, 查找, 修改
这三步操作是围绕查找来, 由于单链表结构的特点, 所以只能做到顺序查找(可采用平衡二叉搜索树, 实现链表的O(logn)的复杂度)
上代码:

LNode *find(LNode *L,char *e){while(L!=NULL){//避免引用非法指针if(strcmp(L->data.name,e)==0)return L;L=L->next;}return head; 
}

传入head节点, 以及所要查找的元素e(使用指针, 其效果与char e[]一致), 不断比较, 成功则返回所指向的节点, 失败则返回head

删除: 删除我做了修改, 让它具有两个功能–删除特定元素, 删除整个链表(其实还是为了偷懒, 少写代码)

void remove(LNode *L,LNode *LTarget_value){while(L->next!=NULL){if((L->next==LTarget_value)&&(LTarget_value!=NULL)){//用于删除特定元素LNode* p=L->next;L->next=p->next;//将所要删除的节点进行分离操作size--;//删除一个人就需要总人数减一次delete p;return;//若删除p立马退出 }else if(LTarget_value==NULL){//用于删除整个链表LNode* p=L->next;L->next=p->next;delete p;//分离一个节点进行一次删除,直到删除到只剩下head节点才停止}if(LTarget_value!=NULL) L=L->next;//只有在删除特定元素的时候才进行L的移动 }if(LTarget_value==NULL) delete L;//只有在删除整个链表才删除head
}

修改操作: 修改可针对特定元素, 此处只做简单说明
上代码:

void revise(LNode *L,char *e,char *Ae,int i){LNode *p=find(L,e);if(p->data.name==NULL && p->data.num=NULL )return;//表示没有找到要修改的元素,p现在是head,head里面没有存数据, 直接跳出程序if(i==1)	strcpy(p->data.name,Ae);else if(i==2)	strcpy(p->data.num,Ae);
}

L表示head, e表示要查找的目标元素, Ae表示替换e, i表示选择替换name, 还是替换num

输出
输出就很简单了, 不做叙述

void display(LNode *L){while(L!=NULL){printf("%s %s\n",L->data.name,L->data.num);L=L->next;}
}

此次测试所用的结构体

struct DataType{char name[10];char num[12]; 
}; 
struct LNode{LNode *next;DataType data;
};

两个全局变量

LNode *head=new LNode();//head节点
int size=0;//用作计数, 计算存入多少联系人

main函数 的测试代码

int main(){int t_size;int sum=0,i;char na[10],nu[12];  printf("输入需要创建的电话本大小以及1.头插OR2.尾插\n");scanf("%d%d",&t_size,&i);while(sum<t_size){printf("输入名字,号码\n");fflush(stdin);scanf("%s%s",na,nu);LNode *s=new LNode();s->next=NULL;strcpy(s->data.name,na);strcpy(s->data.num,nu);size++; //每输入一次,size进行一次增加, 只有在输入才有人数的增加if(i==1){//输入时选择头插法,还是尾插法insertHead(head,s);}else if(i==2){insertTail(head,s,sum);}++sum;}display(head);
//	printf("输入要查找的元素\n");fflush(stdin); 
//	scanf("%s",na);
//	printf("%s\n",find(head,na)->data.name);
//	printf("删除链表中元素\n");fflush(stdin); 
//	scanf("%s",na);
//	if(i==1){
//		puts("输入要删除的元素");scanf("%s",na);
//		remove(head,find(head,na));
//	} 
//	display(head);
//	puts("若号码以及名字都要修改那么你可选择直接删除");
//	puts("需要修改的元素,修改后的值,1.修改名字,2.修改号码");
//	scanf("%s%s%d",na,nu,&i);
//	revise(head,na,nu,i);puts("输入在几号位置进行插入操作,插入元素为,0号是首元素");scanf("%d",&i);printf("输入名字,号码\n");fflush(stdin);scanf("%s%s",na,nu);LNode *s=new LNode();s->next=NULL;strcpy(s->data.name,na);strcpy(s->data.num,nu);insert(i,head,s);
//	convert(head);display(head);remove(head,NULL); return 0;
}

代码进行拼凑就可使用, 可能存在异常, 但是主要还是阐述思想, 上面注释部分为测试每个功能的代码, 最后还需做修改, 写的不好, 还有很多地方需要改进, 就不做修改了, 界面做的很简陋, 整个程序最核心的还是insert, find, remove, 理解头插法与尾插法的区别, 有问题还请在下方留言

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468759.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

有意思的BAT CMD if while循环 整型自增

引言 我们开发过程中经常遇到写bat进行测试的&#xff0c;需要对这方面有些基础&#xff0c;我给出个示例&#xff0c;也方便自己以后工作做参考。 echo off title qifa :looprem setlocal enabledelayedexpansionset /a a1 echo loop %a%choice /t 1 /d y /n >nulrem 判断…

ufldl学习笔记与编程作业:Multi-Layer Neural Network(多层神经网络+识别手写体编程)...

ufldl学习笔记与编程作业&#xff1a;Multi-Layer Neural Network(多层神经网络识别手写体编程) ufldl出了新教程&#xff0c;感觉比之前的好&#xff0c;从基础讲起&#xff0c;系统清晰&#xff0c;又有编程实践。 在deep learning高质量群里面听一些前辈说&#xff0c;不必深…

sql查询无结果返回空_3分钟短文 | Laravel 查询结果检查是不是空,5个方法你别用错...

引言Laravel 提供了 Eloquent ORM 对象用于操作数据库&#xff0c;将其进行抽象方便操作。因为设计的灵活度&#xff0c;大家在使用Model查询数据集的时候&#xff0c;会面临结果为空&#xff0c;记录不存在的问题&#xff0c; 那么如何有效地判断查询记录为空呢&#xff1f;本…

Android 7.1 bootchart触发后导致不断重启

android7.1 bootchart android 7.1的bootchart问题比较多&#xff0c;之前的版本还是比较稳定的&#xff0c;但是7.1之后出现了问题。 由於7.0 bootchart.cpp中有bug, google在7.1上還沒有修复&#xff0c;当我们执行下面的命令后 adb shell echo 120 > /data/bootchart/st…

深度优先搜索小结

深度优先搜索(DFS) 深度优先搜索就好比走迷宫, 不断顺着一条路走, 直到走不通为止, 然后回退到上一个路口再向另外的方向行走(走过的方向就不会再走了,又不是傻子, 知道走不通,还向走不通的方向走), 不断重复(试过所有路口, 状态转移), 重复直到找到唯一的一条合适的路径; DFS…

python 串口_如何使用Python开发串口通讯上位机(一)

用Python开发串口通讯型上位机&#xff0c;其实并非最优解&#xff0c;本系列更新只为个人学习与总结。如果有C语言底子&#xff0c;嵌入式层面的上位机开发&#xff0c;C Builder&#xff0c;C#才是更加好用的利器。1什么是上位机从事过嵌入式软件开发或者工控机开发的&#x…

[RK3399 Android7.1] 开启保存上一次重启前日志

保存上一次重启前日志的必要 分析死机的情况需要我们把上一次不能及时抓取的日志拿到是非常关键的&#xff0c;这个方法非常有利于我们分析内核panic和Android 死机的情况。 开启的方法 内核配置 在dts文件里面添加下面两个节点 ramoops_mem: ramoops_mem { reg <0x0 …

算法题之求二叉树的最大距离

二叉树是一种非常经典的数据结构。如果我们把二叉树看成一个图&#xff0c;父子节点之间的连线看成是双向的&#xff0c;我们姑且定义"距离"为两节点之间边的个数。写一个程序求一棵二叉树中相距最远的两个节点之间的距离。 下面我们随意构造出一棵二叉树&#xff0c…

MySQL基本操作指令

MySQL 注: MySQL对大小写不敏感, 需要对大小检索, 使用关键字binary, "[]"中内容为可选内容; table_name, tableName表示表名, columnName表示列名, DataType表示表中列数据类型, 粗体部分表示关键字 创建数据库: create database [if not exits] 数据库名;删除数据…

php 公众号验证回调方法_微信公众号关键词自动回复设置方法!

什么是公众号关键词自动回复&#xff1f;在微信公众号平台设置关键词自动回复&#xff0c;可以通过添加规则&#xff0c;关注/订阅的用户发送的消息内容如果是你设置的关键字&#xff0c;即可以实现自动回复预先设置好的内容。关键字自动回复设置方法&#xff1a;1、 首先我们进…

图文|Android 使用Thread 和多线程使用互斥锁

为什么需要多线程进行开发&#xff1f;多线程不管是嵌入式系统RTOS&#xff0c;Linux&#xff0c;还是应用开发&#xff0c;中间件开发&#xff0c;都是必不可少的&#xff0c;做一个技术的时候&#xff0c;如果能做到举一反三&#xff0c;下次使用的时候不会再遇到坑&#xff…

01.轮播图之三 : collectionView 轮播

个人觉得 collection view 做轮播是最方便的&#xff0c;设置下flowlayout 其他不会有很大的变动&#xff0c;没有什么逻辑的代码 lets begin…… 创建自定义的view .h 声明文件 interface CollectionViewShuffling : UIViewproperty (nonatomic,strong)NSArray *array;end .m …

JDBC入门级操作

JDBC:数据库连接, 通过接口实现不同数据库之间的切换, 面向接口编程 JDBC驱动程序将JDBC调用映射成特定的数据库调用 驱动类型: 1.JDBC驱动:JDBC-ODBC桥,最早的实现方式,将JDBC API映射到ODBC API,Java8中已删除 2.直接将JDBC API映射成数据库特定的客户端API,次驱动包含特定数…

手机调试python的软件_Appium+Python(ios真机移动端App H5混合自动化实战测试)

一、环境搭建篇(一)安装JDK大家自行安装(二)安装Appium1、appium desktop2、appium server> brew install node # get node.js> npm install -g appium # get appium> npm install wd # get appium client> appium & # start appium> node your-appium-test…

计算机专业的学生该选择日后的人生道路?继续从事IT还是考公务员……

问题来自知乎原问题如下&#xff1a;知乎上的盆友们大家好&#xff01;我是某高校大二学生。万能的知友们&#xff0c;有相关经验的大家给点宝贵意见呗&#xff0c;万分感谢。个人问题&#xff1a;我当时是听说这一行工资高&#xff0c;因为家里条件一般&#xff0c;所以想要挣…

file_put_contents()写入数组

file_put_contents()写入数组 $arr array(name>张三&#xff0c;‘age’>26, sex>男 ) $str var_export($arr,TRUE); file_put_contents($filename,$str);转载于:https://www.cnblogs.com/icefei/p/6773916.html

JVM垃圾收集器与内存分配策略学习总结

方法区: 1.线程共享 2.储存类信息,常量,静态变量,编译器编译后的代码 3.非堆(别名)用于区分Java堆 4.不需要连续的内存 5.可以固定或可扩张 6.选择不实现垃圾回收//这个区域很少进行垃圾回收 7.针对常量池回收 8.对类型的卸载 9.无法满足内存分配需求抛出OutOfMemoryError4 虚…

汇编比较两个数大小_计算机是怎样跑起来的 -- 体验一次汇编过程

标志内存或I/O中存储单元的数字叫做“地址”。CPU中的标志寄存器有什么作用&#xff1f;用于在运算指令执行后&#xff0c;存储运算结果的某些状态。从程序员的角度看硬件CPU&#xff1a;种类&#xff0c;时钟信号的频率。可以使用哪种机器语言取决于CPU的种类。内存信息&#…

Nginx 作为 WebSockets 代理

WebSocket 协议给我们提供了一个创建可以支持客户端和服务端进行双向实时通信的web应用程序的方法。相比之前使用的方法&#xff0c;WebSocket&#xff08;作为HTML5的一部分&#xff09;可以使我们更容易开的发出这种类型的应用程序。绝大多数的现代浏览器都支持WebSocket&…

设计模式小结

开始的毛病:变量命名不规范,if-else判断有的代码做无用功,代码健壮性太差,没有做try-cath异常处理 工厂模式(创建型模式): 创建对象接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建延伸到子类进行 主要解决接口选择问题,明确计划不同条件下执行创建不同实例 通过子…