PAT 1025. 反轉連結串列 (25)---最後一個測試點的坑點
阿新 • • 發佈:2019-01-30
題目描述:
給定一個常數K以及一個單鏈表L,請編寫程式將L中每K個結點反轉。例如:給定L為1→2→3→4→5→6,K為3,則輸出應該為3→2→1→6→5→4;如果K為4,則輸出應該為4→3→2→1→5→6,即最後不到K個元素不反轉。
輸入格式:
每個輸入包含1個測試用例。每個測試用例第1行給出第1個結點的地址、結點總個數正整數N(<= 105)、以及正整數K(<=N),即要求反轉的子鏈結點的個數。結點的地址是5位非負整數,NULL地址用-1表示。
接下來有N行,每行格式為:
Address Data Next
其中Address是結點地址,Data是該結點儲存的整數資料,Next是下一結點的地址。
輸出格式:
對每個測試用例,順序輸出反轉後的連結串列,其上每個結點佔一行,格式與輸入相同。
輸入樣例:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
輸出樣例:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1
題目分析:
題目要求將k個結點進行逆轉,等於將連結串列分成了n/k段(這裡的n指的是結點的有效個數,即在連結串列上的結點),每段有k個節點,將每段逆轉過來後再連線到一塊。這種操作很容易想到先進後出的zhan,即將每一段進棧,之後在依次輸出到佇列中,重複操作每一段。直到所有段中的結點都已經進入佇列,最終將連結串列中剩餘的不夠一段的結點進入佇列。最後輸出之前記得更新結點的next,將它們重新連結在一塊。
注意點:
#include<stdio.h>
#include<stack>
#include<queue>
using namespace std;
const int maxn=100000; //定義最大連結串列結點數
struct node{
int address,data,next; //結點結構體,成員有地址address,資料域data,指標域next
}num[maxn];
int main()
{
int address,begin,n,k; //臨時存放結點地址的address,存放首地址的begin,結點數n,逆轉結點數k
stack<node> s; //臨時存放逆轉結點的棧
queue<node> q; //存放逆轉後的序列
scanf("%d%d%d",&begin,&n,&k);//讀入
for(int i=0;i<n;i++){
scanf("%d%",&address);
num[address].address =address;
scanf("%d%d",&num[address].data,&num[address].next); //讀入每個結點的資訊
}
int p=begin,cnt=0,count=0; //p為工作指標,cnt記錄當前已經進入棧中的逆轉結點數。count記錄有效結點數
while(p!=-1){
count++;
p=num[p].next; //遍歷連結串列統計結點個數
}
p=begin; //p指標回到首位
for(int i=1;i<=count/k;i++){ //逆轉次數,迴圈
while(cnt!=k*i){ //只要需要逆轉的結點數沒到時
cnt++;
s.push(num[p]); //入棧
p=num[p].next;
}
if(cnt==k*i){ //本次逆轉完畢
while(!s.empty()){
q.push(s.top()); //將棧中所有的元素輸出到佇列中
s.pop();
}
}
}
while(p!=-1){ //把連結串列中剩餘的不許逆轉的結點入佇列
q.push(num[p]);
p=num[p].next ;
}
while(!q.empty()){ //輸出
node temp;
temp=q.front();
q.pop();
temp.next =q.front().address; //按照逆轉後的新順序,更新結點的next
if(q.size()>=1){
printf("%05d %d %05d\n",temp.address,temp.data,temp.next);
}
else {
temp.next =-1; //最後一個結點要特別判斷
printf("%05d %d %d\n",temp.address,temp.data,temp.next);
}
}
return 0;
}