02-线性结构3 Reversing Linked List (25 分)

Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K=3, then you must output 3→2→1→6→5→4; if K=4, you must output 4→3→2→1→5→6.
Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (≤10​0000​​ ) which is the total number of nodes, and a positive K (≤N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:
Address Data Next
where Address is the position of the node, Data is an integer, and Next is the position of the next node

1.该题改编于微软的一道面试题,所以是英文。其大概意思是:给你一个广义上的链表,并给出以下数据:
第一行:首地址 节点数N 所需反转的节点数K
后N行:节点地址 节点所存数据 节点所指的下一节点地址

题目要求每K个反转一次;
e.g.
N=4;sentry->a->b->c->d //sentry为哨兵节点
(1).K=3 故得sentry->c->b->a->d;
(2).K=2故得sentry->b->a->d->c;

2.节点定义:

struct Node {
	int val;
    int next;
    Node(){}
    Node(int val_,int next_):val(val_),next(next_){}
};

我们选用结构数组模拟,不用链表(动态申请)的原因是:
(1).一般我们定义Node* p=new Node;便可以用"p->next"等进行对申请的节点操作,但是这里所给的地址是int型,若定义 int p=first_Address;不可以使用"p->next"等;
(2).所给N<100000;那我们开一个100000+1大小的结构数组,多出的“1”,作为哨兵节点(sentry).
3.链表类的申明:

class List{
private:
	const int sentryAddr=100000;
	//哨兵节点的下表为100000(常用),故用sentry代替之
	struct Node array[100001];
	//下表 0~100000 真正储存数据的节点下表为0~99999(100000个);
public:
	List(int firAddr);
	//构造函数中初始化一个哨兵节点(sentry)
	void read(int addr,int val,int next);
	//将每个节点接入
	const void disPlay();
	//按格式打印每个节点
	int getLen();
	//获得真实有用的链表长度(链表长度!=N)
	void reverse(int K);//逆转链表的函数
};

4.格式化输出:
e.g.把 1 输出成 01;

#include <iostream> //引用相关输出头文件
#include <iomanip> //引用格式控制头文件
using namespace std ; 
int main()
{
    int a=1;
    cout.setf(ios::right);      //设置对齐方式为右对齐 
    cout.fill('0');             //设置填充方式,不足位补0
    cout.width(2);              //设置宽度为2,只对下条输出有用 
    cout<<a<<endl; 
    return 0;
}

5.总代码为:

#include <iostream>
#include <iomanip>
using namespace std;
struct Node {
	int val;
    int next;
    Node(){}
    Node(int val_,int next_):val(val_),next(next_){}
};

class List{
private:
	const int sentryAddr=100000;
	struct Node array[100001];
public:
	List(int firAddr){
		for(int i=0;i<=sentryAddr;++i)
			array[i].next=-1;
		array[sentryAddr].next=firAddr;
		//初始化得一个哨兵节点 
	}
	void read(int addr,int val,int next){
		array[addr].val=val;
		array[addr].next=next;
	}
	const void disPlay(){
		int p=array[sentryAddr].next;
		while(p!=-1){
			cout.setf(ios::right);//网上查得输出格式 
			cout.fill('0');
			cout.width(5);
			
			cout<<p<<" "<<array[p].val<<" ";
			if(array[p].next==-1){
				cout<<"-1";//最后一行打印后无需再打印换行了 
			}else{
				cout.setf(ios::right);
				cout.fill('0');
				cout.width(5);
				cout<<array[p].next<<endl;
			}
			p=array[p].next;
		}
	}
	int getLen(){
		int p=array[sentryAddr].next;
		int cnt=0;
		while(p!=-1){
			p=array[p].next;
			cnt++;
		}
		return cnt;
	}
	void reverse(int K){
		int cnt;
		int head=array[sentryAddr].next;//至少一个节点 
		int link;//link保存逆转了的链表尾节点,保证后面的逆转衔接正常
		if(K==1)
			return;//故以下 节点数至少为2
		int New,Old;
		int len=getLen();
		for(int i=0;i<len/K;++i){
			New=head;
			Old=array[New].next;
			cnt=1;
			while(cnt<K){
				int Tmp=array[Old].next;
				array[Old].next=New;
				New=Old;
				Old=Tmp;
				cnt++;
			}
			array[head].next=Old;
			/*
			  下面是为了保存链表的头
			  sentryAddr为哨兵得地址,固定值100000 
			  head保存还未逆转的链表头
			  link保存逆转了的链表尾节点,保证后面的逆转衔接正常
			*/ 
			if(i==0)
				array[sentryAddr].next=New;
			else
				array[link].next=New;
			link=head;
			head=Old;
		}
	}
};

int main()
{	
	int addr,next,N,K,val;
	cin>>addr>>N>>K; //第一行 首地址 节点个数N K
	List L(addr);
	for(int i=0;i<N;++i){
		cin>>addr>>val>>next;
		L.read(addr,val,next);
	}
	L.reverse(K);
	L.disPlay();
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值