Reversing Linded list【数据结构测试2.1】

2024-01-22 10:08

本文主要是介绍Reversing Linded list【数据结构测试2.1】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

PAT 1074. Reversing Linked List,作为课后题出现在数据结构MOOC上。
刚开始学数据结构,水平还差的远尴尬 ,参考网上code,参考:http://tech-wonderland.net/blog/pat-1074-reversing-linked-list.html
路漫漫其修远兮奋斗

也是刚开始没有理解好题目意思,导致有几处感觉有难度,后来才发现是想多了。
几个需要注意的地方:
1、链表反转长度K要注意分情况讨论:<1的时候,>链表长度N的时候, =2的时候(此处要注意输入数据是多链表的时候,要修正有效链长)
2、只有1个节点的时候,输出问题
3、输入数据的K>N的时候,还是要注意重新修正有效链长,与1中提到的情况关联,否则可能会出现死循环的情况

详细讨论在代码后面:(代码为了方便自己以后看,注释较多= =)
#include "stdafx.h"
#include <fstream>
#include<vector>  
#include <iostream>
#include <iomanip>
using namespace std;  const int MaxSize = 100004;
int ihead;//头结点
int N,K;//node个数N,需要反转的node个数K
struct Node{int iData;int iNext;
};Node NodeList[MaxSize];//链表void doPrint(int ilisthead)//输入表头,输出整表
{while(-1 != ilisthead){if(NodeList[ilisthead].iNext == -1)//只有一个节点或者多个链表的时候只打印第一个{cout<<setw(5)<<setfill('0')<<ilisthead<<" "<<NodeList[ilisthead].iData<<" "<<"-1"<<endl;break;}cout<<setw(5)<<setfill('0')<<ilisthead<<" "<<NodeList[ilisthead].iData<<" "<<setw(5)<<setfill('0')<<NodeList[ilisthead].iNext<<endl;ilisthead = NodeList[ilisthead].iNext;//指向下个节点}
}//反转指定长度的节点(一次)
int reversK(int istart,int ik,int *phead,int *ptail)
{if(-1 == istart || ik <= 1)return -1;if(2 == ik){int node1 = istart;int node2 = NodeList[istart].iNext;NodeList[node1].iNext = NodeList[node2].iNext;//交换头尾NodeList[node2].iNext = node1;*phead = node2;//向后移动*ptail = node1;return 0;}// >=3的情况*ptail = istart;//保存表头,作为最后的表尾int node1 = istart;int node2 = NodeList[istart].iNext;int nodeTmp = -1;for(int i = 0; i < ik - 1; ++i)//反转ik个节点需要改变ik-1个连接关系{//暂存node2下个元素地址后改为指向node1nodeTmp = NodeList[node2].iNext;NodeList[node2].iNext = node1;//node1,node2同时向后移动node1 = node2;node2 = nodeTmp;}*phead = node1;//原来最后一个元素作新的表头NodeList[*ptail].iNext = node2;//新表尾指向node2,下一个元素或者NULL(所有元素处理完)//cout<<node2<<endl;return 0;
}void process(){//将整个链表反转//get the Effective Lenthgthint itemp = ihead;int iEffectiveLenth = 1;//链表有效长度while(-1 != NodeList[itemp].iNext) {			++iEffectiveLenth;			itemp = NodeList[itemp].iNext;			}				if(K > iEffectiveLenth) {					doPrint(ihead);	return;}	N = iEffectiveLenth;//注意!!此处细节也不可忽略,处理链表的时候需要重新设定链表的有效长度,因为在输入是多个链表的情况下有可能会出错//cout<<N<<endl;int inewhead;if(K > 1){int iheadtmp,itailtmp;int ilasttail;//记录上次反转的尾部//先反转一次,并记录翻转后的头尾reversK(ihead,K,&iheadtmp,&itailtmp);inewhead = iheadtmp;//注意!!此处inewhead是有用的,第一次反转以后,新的链表头已经产生了,即原来的链表的第K个节点!因此下面输出链表的时候要从这个新的节点开始输出!ilasttail = itailtmp;int revcount = N / K -1;//剩余反转次数for(int i = 0; i < revcount; ++i){reversK(NodeList[itailtmp].iNext,K,&iheadtmp,&itailtmp);NodeList[ilasttail].iNext = iheadtmp;//上一次反转后尾部指向此次反转完成的头(本来指向此次反转前的尾部)(不好理解的话见下面!示意图!)ilasttail = itailtmp;			}}else//K<=1的时候新的表头还是原来的表头inewhead = ihead;doPrint(inewhead);//从新的表头开始输出}
int main()  
{ fstream cin("a.txt");for(int i  = 0; i < MaxSize; ++i)//initial the whole list{NodeList[i].iData = 0;NodeList[i].iNext = -1;}cin>>ihead>>N>>K;int iadd,idata,inext;for(int i = 0; i < N; ++i)//读入链表{cin>>iadd>>idata>>inext;NodeList[iadd].iData = idata;NodeList[iadd].iNext = inext;}process();return 0;
}

关于几点注意的讨论:
1、process()函数最后那个循环里注释部分的示意图:

2、容易忽略的一个小细节,即当输入数据不止一个串的时候要及时更新有效长度,即只处理第一个串。

N = iEffectiveLenth;//此句注意,不可忽略,处理链表的时候需要重新设定链表的有效长度,因为在输入是多个链表的情况下有可能会出错(陷入死循环,配合上图和下面的讨论不难理解)
测试数据:(多串情况)
00100 6 3
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 -1


<pre name="code" class="cpp">for(int i = 0; i < ik - 1; ++i)//反转ik个节点需要改变ik-1个连接关系{//暂存node2下个元素地址后改为指向node1nodeTmp = NodeList[node2].iNext;NodeList[node2].iNext = node1;//node1,node2同时向后移动node1 = node2;node2 = nodeTmp;}

 

N影响的是下面的循环次数,而下面的又调用了上面的这段函数,因此当使用最上面的数据的时候,当k=2的时候,正确的情况应该是,由于有多个链表,N需要重新设定有效长度,重新设定以后应该为2,因此,下面的程序只循环一次;
但当N不重新设定有效长度的时候,循环次数为两次,循环过两次之后的情况就是,节点1指向节点2,节点2指向-1,(由于-1的下个节点还是-1,)因此再一次循环的时候,再执行下面的语句:
nodeTmp = NodeList[node2].iNext;NodeList[node2].iNext = node1;//node1,node2同时向后移动node1 = node2;node2 = nodeTmp;

然后,节点2就指向了节点2本身了。
且节点2作为头结点,因此输出的时候形成死循环。


这篇关于Reversing Linded list【数据结构测试2.1】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/632652

相关文章

Java中List的contains()方法的使用小结

《Java中List的contains()方法的使用小结》List的contains()方法用于检查列表中是否包含指定的元素,借助equals()方法进行判断,下面就来介绍Java中List的c... 目录详细展开1. 方法签名2. 工作原理3. 使用示例4. 注意事项总结结论:List 的 contain

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

java streamfilter list 过滤的实现

《javastreamfilterlist过滤的实现》JavaStreamAPI中的filter方法是过滤List集合中元素的一个强大工具,可以轻松地根据自定义条件筛选出符合要求的元素,本文就来... 目录1. 创建一个示例List2. 使用Stream的filter方法进行过滤3. 自定义过滤条件1. 定

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

python中列表list切分的实现

《python中列表list切分的实现》列表是Python中最常用的数据结构之一,经常需要对列表进行切分操作,本文主要介绍了python中列表list切分的实现,文中通过示例代码介绍的非常详细,对大家... 目录一、列表切片的基本用法1.1 基本切片操作1.2 切片的负索引1.3 切片的省略二、列表切分的高

java两个List的交集,并集方式

《java两个List的交集,并集方式》文章主要介绍了Java中两个List的交集和并集的处理方法,推荐使用Apache的CollectionUtils工具类,因为它简单且不会改变原有集合,同时,文章... 目录Java两个List的交集,并集方法一方法二方法三总结java两个List的交集,并集方法一

Java集合中的List超详细讲解

《Java集合中的List超详细讲解》本文详细介绍了Java集合框架中的List接口,包括其在集合中的位置、继承体系、常用操作和代码示例,以及不同实现类(如ArrayList、LinkedList和V... 目录一,List的继承体系二,List的常用操作及代码示例1,创建List实例2,增加元素3,访问元

SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程

《SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程》本文详细介绍了如何在虚拟机和宝塔面板中安装RabbitMQ,并使用Java代码实现消息的发送和接收,通过异步通讯,可以优化... 目录一、RabbitMQ安装二、启动RabbitMQ三、javascript编写Java代码1、引入

Nginx设置连接超时并进行测试的方法步骤

《Nginx设置连接超时并进行测试的方法步骤》在高并发场景下,如果客户端与服务器的连接长时间未响应,会占用大量的系统资源,影响其他正常请求的处理效率,为了解决这个问题,可以通过设置Nginx的连接... 目录设置连接超时目的操作步骤测试连接超时测试方法:总结:设置连接超时目的设置客户端与服务器之间的连接

Go语言中三种容器类型的数据结构详解

《Go语言中三种容器类型的数据结构详解》在Go语言中,有三种主要的容器类型用于存储和操作集合数据:本文主要介绍三者的使用与区别,感兴趣的小伙伴可以跟随小编一起学习一下... 目录基本概念1. 数组(Array)2. 切片(Slice)3. 映射(Map)对比总结注意事项基本概念在 Go 语言中,有三种主要