数据结构————链表及其简单应用2
来源:互联网 发布:同方软件股份有限公司 编辑:程序博客网 时间:2024/06/05 06:15
链表及其简单应用2
1.前言
- 在我的上一篇博客中,介绍和链表是什么和链表的基本操作,即创建输出,增删改查。这些是链表应用的基础,几乎所有链表的应用都是在这些的基础上进行的延伸和融合。所以对于链表的基本操作一定要做到熟练掌握。
- 在我的上篇博客中还写了一些关于链表的应用。
- 升序合并
- 基于链表的冒泡和插入排序
- 删除a链中于b链重复的节点
- n个小孩报数问题
- 简单的学生管理系统
- 在上篇博客写完后,又学习了一些关于链表的应用,所以写这片博客跟大家分享一下
- 链表的逆置
- 两个升序合并为降序
- 两个长度不同的链表交叉合并
- 简易通讯录
- 约瑟夫环问题
2.链表的逆置
1. 方法一
- 思路:
灵活运用头插法进行逆置,初始为一个头节点,找一个临时指针存下一个节点地址,将下一个节点以头插法的形式插入(插入前备份指针域)。 - 核心代码
//插入节点的指针域(下一个节点的地址)备份pTemp1=pTemp2;pTemp2=pTemp1->next;//头插pTemp1->next=pHead->next;pHead->next=pTemp1;
- 完整代码
void contrary(struct node *pHead){ struct node *pTemp1=pHead->next,*pTemp2=pHead->next; pHead->next=NULL; while(pTemp2) { pTemp1=pTemp2; pTemp2=pTemp1->next; pTemp1->next=pHead->next; pHead->next=pTemp1; }}
- 完整代码地址(包含创建和输出)
- 点我查看
- 或者点我查看
2. 方法二
- 思路:
从第一个节点开始,改变每个节点的指针域指向,直到最后一个节点,是否原来不存数据的头节点,新申请一个头节点 - 核心代码
pi_q=pi;//移动 pi=pi_h;pi_h=pi->next;//改变指向pi->next=pi_q;pi——当前要改变的节点pi_q——当前要改变的节点前节点pi_h——当前要改变的节点后节点
- 完整代码
struct lianbiao *Nizhi(struct lianbiao *pHead){ struct lianbiao *pi=pHead,*pi_q,*pi_h=pHead->next,*p; while(pi_h) { pi_q=pi;//移动 pi=pi_h; pi_h=pi->next; pi->next=pi_q; } free(pHead); pHead->next->next=NULL;//原来头部指针清0 p=(struct lianbiao *)malloc(sizeof(struct lianbiao)); p->next=pi; return p;}
- 完整代码地址(包含创建和输出)
- 点我查看
- 或者点我查看
2. 两个升序链表合并为降序
1. 方法一
- 将俩个升序链表合并升序链表,再调用上面的(逆置)函数进行逆置
- 代码地址
2.方法二
- 思路
类似于两个升序链表合成一个升序链表,使用3个指针,a,b.a指向La链表链表当前节点,b指向Lb链表的当前节点,比较a,b所指的节点数据域大小,将小的以头插的方式插到La头节点后(插入前备份),然后小的后移。 - 核心代码
//备份和移动La_t=La->next;La->next=pHead_a->next;//头插pHead_a->next=La;La=La_t;
- 完整代码
void merge(struct node *pHead_a,struct node *pHead_b){ struct node *La,*Lb,*Lc,*La_t,*Lb_t; La=pHead_a->next; Lb=pHead_b->next; pHead_a->next=NULL; while(La&&Lb) { if((La->date)<(Lb->date)) { La_t=La->next; La->next=pHead_a->next; pHead_a->next=La; La=La_t; } else { Lb_t=Lb->next; Lb->next=pHead_a->next; pHead_a->next=Lb; Lb=Lb_t; } } while(La)//假如b链表遍历完,a链表未遍历完,将a链表剩下的节点进行头插 { La_t=La->next; La->next=pHead_a->next; pHead_a->next=La; La=La_t; } while(Lb) { Lb_t=Lb->next; Lb->next=pHead_a->next; pHead_a->next=Lb; Lb=Lb_t; }}
- 完整代码地址(包含创建和输出)
- 点我查看
- 或者点我查看
3.交叉合并
- 题意要求
将两个长度不一样的链表进行交叉合并(即a1,b1,a2,b2),并以长度短的为开头。当短的排完后,剩下的节点全部为长链表 - 思路
使用Lx,Ly,Lz三个指针,Lx指向短链表,Ly指向长链表,Lz指向已排好序的链表尾部,使用指针通过Lz,Lx,Ly将它们交叉串起来 - 核心代码
Lz->next=Lx; //连接lz和短链表的当前节点Lx_h=Lx->next;//备份Lx的指针域Lx->next=Ly;//连接Lx当前节点和Ly当前节点Lz=Ly;//移动lz,使lz成为当前已排好节点的尾部Lx=Lx_h;//移动lx,使lx成为短链表未排好序的第一个Ly=Ly->next;//移动ly,使ly成为长链表未排好序的第一个
- 完整代码
void merge(struct node *pHead_x,struct node *pHead_y){ struct node *Lx,*Lx_h,*Ly,*Lz; Lx=pHead_x->next; Ly=pHead_y->next; Lz=pHead_x; while(Lx) { Lz->next=Lx; Lx_h=Lx->next; Lx->next=Ly; Lz=Ly; Lx=Lx_h; Ly=Ly->next; } Lz->next=Ly; }
- 完整代码地址(包含创建和输出)
- 点我查看
- 或者点我查看
4.简单通讯录
- 题意:
通信录应该包括联系人姓名,电话,类别
实现通讯录的信息的增删改查
拓展:输出按人名的字典顺序输出 - 思路
这道题是链表的使用链表的基本操作,创建,遍历,增删改查,排序的糅合 - 完整代码地址
- 点我查看
- 或者点我
5.约瑟夫环
1. 基本款
- 题意:
n个人按顺时针方向围坐在一张圆桌周围,每个人手中持有一张密码。 一开始任选将第一个人的密码牌作为报数上限m,从第一个人开始从1报数,直到报到m为止,报道m的人出队,将他的密码作为新的m,继续报数,重复直到只剩一个人的时候停止。要求密码随机 - 思路:
- 创建一个循环链表(和单链表相比,头节点存数据,尾节点指针域存头指针)。每个节点的数据域由两部分构成,序号和密码,密码由随机函数rand()产生随机数,序号由建立时依次填入。
- 进行循环,先使用指针找到报到m的节点(人),再对这个节点进行删除操作(不释放空间)。然后将这个节点的密码赋给m,输出本次出队结果。然后再进行循环。
- 循环的停止,当指针的和他的指针域相同时,出循环。此时剩下的节点为最后一个人。
- 核心代码
while(pi!=pi->next) { for(i=0;i<M-1;i++)//寻找本次需要删除的节点 { pi_q=pi; pi=pi->next; } M=pi->num;//换密码 pi_q->next=pi->next;//出队 pi=pi->next;//移动` }
- 完整代码
struct node *f1(struct node *pHead,int iCound){ struct node *pi=pHead,*pi_q=pHead->next; int i,M,a[Long]={0},j; while(pi_q->next!=pi) pi_q=pi_q->next; M=pi->num; while(pi!=pi->next) { for(i=0;i<M-1;i++)//寻找本次需要删除的节点 { pi_q=pi; pi=pi->next; } printf("本次密码为%d ",M);//输出查看 printf("本次序号为%d出队\n",pi->NO); a[pi->NO]++;//表示出队 printf("已出队:"); for(j=0;j<Long;j++) if(a[j]!=0) printf("%-5d",j); printf("\n还在队中:"); for(j=0;j<iCound;j++) if(a[j]==0) printf("%-5d",j); printf("\n\n"); M=pi->num;//换密码 pi_q->next=pi->next;//删除 pi=pi->next; } printf("最后在队中的为%d\n",pi->NO); }
- 完整代码地址
- 点我查看
- 或者点我查看
2. 扩展1:
- 拓展内容:
不从1号开始报数,第一个报数的人随机选择 - 思路:
大致同第一个一样,不过再进循环前找到随机开始的第一个报数人 - 新增代码
M=rand()%(iCound-1)+1;printf("从%d个人开始报数\n",M);for(i=0;i<M-1;i++)//寻找第一个人 { pi_q=pi; pi=pi->next;}M=pi->num;
- 完整代码
void f1_1(){ int j; printf("已出队:"); for(j=0;j<Long;j++) if(a[j]!=0) printf("%-5d",j); printf("\n还在队中:"); for(j=1;j<iCound+1;j++) if(a[j]==0) printf("%-5d",j); printf("\n\n");} struct node *f1(struct node *pHead,int iCound){ struct node *pi=pHead,*pi_q=pHead->next; int i,M; while(pi_q->next!=pi) pi_q=pi_q->next; M=rand()%(iCound-1)+1; printf("从%d个人开始报数\n",M); for(i=0;i<M-1;i++)//寻找第一个人 { pi_q=pi; pi=pi->next; } M=pi->num; while(pi!=pi->next) { for(i=0;i<M-1;i++)//寻找本次需要删除的节点 { pi_q=pi; pi=pi->next; } printf("本次密码为%d ",M);//输出查看 printf("本次序号为%d出队\n",pi->NO); a[pi->NO]++; f1_1(); M=pi->num;//换密码 pi_q->next=pi->next;//删除 pi=pi->next; } printf("最后在队中的为%d\n",pi->NO); }
- 完整代码地址
- 点我查看
- 或者点我查看
3. 拓展2
- 拓展内容:
某个人出队时,再次开始报数,随机从左或从右随机开始报数 - 思路
- 创建一个双向循环链表,与单表相比,指针域分为两部分,左指针和右指针(llink和rlink),左指针指向前一个节点,右指针指向后一个节点,头节点的左指针域存尾节点的地址。尾节点右指针存头节点地址。
- 同二相似,随机选择第一个开始报数的人。选择后进入循环
- 使用rand()函数,若值为0,使用左指针开始向前循环,若值为1,使用右指针开始向后遍历循环
- 同一相似,开始遍历链表到m时,使这个节点出队。
- m重新赋值,再次进行选择方向
- 当节点的左右指针域都存着自己节点的地址时,停止循环。此时,剩下的节点为最后一个人。
- 核心代码
for(i=0;i<M-1;i++)//寻找本次需要删除的节点 { if(order) { pi_q=pi; pi=pi->rlink; pi_h=pi->rlink; } else { pi_h=pi; pi=pi->llink; pi_q=pi->llink; } } if(M==1)//密码为1时进行的处理 { if(order) pi_h=pi->rlink; else pi_q=pi->llink; } pi_q->rlink=pi->rlink;//删除 pi_h->llink=pi->llink; order=rand()%2; 方向选择 if(order) i=pi->rlink; else pi=pi->llink;
- 完整代码
void f1_1(){ int j; printf("已出队:"); for(j=0;j<Long;j++) if(a[j]!=0) printf("%-5d",j); printf("\n还在队中:"); for(j=1;j<iCound+1;j++) if(a[j]==0) printf("%-5d",j); printf("\n\n");} struct node *f1(struct node *pHead,int iCound){ struct node *pi=pHead,*pi_q=pHead->llink,*pi_h=pHead->rlink; int i,M; int order; M=rand()%(iCound-1)+1; printf("从%d个人开始报数\n",M); for(i=0;i<M-1;i++)//寻找第一个人 { pi_q=pi; pi=pi->rlink; pi_h=pi->rlink; } M=pi->num; order=rand()%2; while(pi->llink!=pi&&pi->rlink!=pi) { if(order) printf("本次向右转 "); else printf("本次向左转 "); printf("本次密码为%d ",M); for(i=0;i<M-1;i++)//寻找本次需要删除的节点 { if(order) { pi_q=pi; pi=pi->rlink; pi_h=pi->rlink; } else { pi_h=pi; pi=pi->llink; pi_q=pi->llink; } } if(M==1) { if(order) pi_h=pi->rlink; else pi_q=pi->llink; } printf("本次序号为%d出队\n",pi->NO);//输出查看 a[pi->NO]++; f1_1(); M=pi->num;//换密码 pi_q->rlink=pi->rlink;//删除 pi_h->llink=pi->llink; //free(pi); order=rand()%2; if(order) pi=pi->rlink; else pi=pi->llink; } printf("最后在队中的为%d\n",pi->NO); }
- 完整代码地址
- 点我查看
- 或者点我查看
阅读全文
0 0
- 数据结构————链表及其简单应用
- 数据结构————链表及其简单应用2
- 常用数据结构——队列及其应用
- 常用数据结构——栈及其应用
- 数据结构与算法学习笔记——堆栈及其应用(10以内简单四则计算器)
- 数据结构学习——Huffman树及其应用
- 数据结构学习笔记——栈及其应用
- 数据结构(java)——栈及其应用
- 数据结构—堆排序及其应用(优先级队列)
- 数据结构与算法专题之线性表——栈及其应用
- 数据结构与算法专题之线性表——队列及其应用
- 怎样对10亿个数字快速去重?——浅析位图数据结构及其应用
- 简单数据结构—队列
- 数据结构算法——单链表及其操作
- 数据结构——矩阵及其常用操作
- 数据结构与算法—常用数据结构及其Java实现
- 数据结构实践——顺序表应用
- 数据结构实践——顺序表应用
- java对称加密算法
- #define用法总结
- 多态
- ricci+luic+fence实现HA
- Linux--RH254---unit 1 ipv6网络的管理
- 数据结构————链表及其简单应用2
- 三国鼎立之谁与争锋---Altium Designer,Cadence,PADS
- mySql数据库存储过程打印参数写法
- retrofit和Rxjava结合 recyclerview的应用
- leetcode-19. Remove Nth Node From End of List(删除链表倒数第N个节点)
- 蒙特卡洛和gibbs采样
- Java 集合 使HashMap 按 value 排序
- Ubutnu Desktop 16.04下安装Virtualbox 5.1
- 强化学习课程