PAT A1097 Deduplication on a Linked List消除連結串列上的重複資料 [靜態連結串列 排序]
Given a singly linked list L with integer keys, you are supposed to remove the nodes with duplicated absolute values of the keys. That is, for each value K, only the first node of which the value or absolute value of its key equals K will be kept. At the mean time, all the removed nodes must be kept in a separate list. For example, given L being 21→-15→-15→-7→15, you must output 21→-15→-7, and the removed list -15→15.
給出一個帶有整型鍵值的單鏈表L,你需要把鍵值的絕對值相同的節點移除。對於每一個值K,只有第一個值為K或值得絕對值為K的節點會被保留,同時,所有被移除的節點會被儲存在另外的連結串列中。
Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, and a positive N (≤10^5) which is the total number of nodes. 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 Key Next
where Address
is the position of the node, Key
is an integer of which absolute value is no more than 10^4, and Next
is the position of the next node.
第一行包含第一個節點的地址和正整數N(節點總數) 後面緊跟著N行,
Output Specification:
For each case, output the resulting linked list first, then the removed list. Each node occupies a line, and is printed in the same format as in the input.
對每一個測試用例,首先輸出結果連結串列,然後輸出被移除元素組成的連結串列,每一個節點用一行顯示,輸出格式和輸入格式相同
#include<stdio.h>
#include<algorithm>
const int maxn = 100010;
struct Node{
int address;
int key;
int next;
}node[maxn];
bool temp[maxn]={0};//記錄鍵值是否已存在
int main(){
int start,n;
scanf("%d %d",&start,&n);
int address,key,next;
for(int i=0;i<n;i++){ //接受輸入
scanf("%d %d %d",&address,&key,&next);
node[address].address=address;
node[address].key=key;
node[address].next = next;
}
Node result[n],remove[n]; //分別定義了結果連結串列和移除連結串列
int p=start,index=0,index2=0;
while(p!=-1){ //開始遍歷連結串列
if(temp[abs(node[p].key)]==false){//當前K值是第一次出現
temp[abs(node[p].key)]=true; //做標記
result[index].address=node[p].address; //存到結果連結串列裡
result[index].key=node[p].key;
if(index>0){
result[index-1].next=node[p].address;
}
index++;
}else{ //該刪掉的節點
remove[index2].address=node[p].address;//存到移除連結串列裡
remove[index2].key = node[p].key;
if(index2>0){
remove[index2-1].next=node[p].address;
}
index2++;
}
p=node[p].next;
}
result[index-1].next=-1;
remove[index2-1].next=-1;
//列印結果
for(int i=0;i<index-1;i++){
printf("%05d %d %05d\n",result[i].address,result[i].key,result[i].next);
}
printf("%05d %d -1\n",result[index-1].address,result[index-1].key);
for(int i=0;i<index2-1;i++){
printf("%05d %d %05d\n",remove[i].address,remove[i].key,remove[i].next);
}
printf("%05d %d -1\n",remove[index2-1].address,remove[index2-1].key);
return 0;
}
提交結果
演算法筆記上的參考程式碼:
增加了一個order變數,對於未刪除的結點,令order從0開始編號。對於需要刪除的結點,令order從maxn開始編號。order初始化為2*maxn,即無效節點的order就是2*maxn.
根據order進行排序,最前面便是未刪除結點,中間是刪除節點,最後是無效節點。用兩個變數記錄未刪除結點和刪除節點的數量,最後輸出。
相對我的想法來說減少了空間複雜度
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100005;
const int TABLE = 1000010;
struct Node{
int address,data,next;
int order;//節點在連結串列上的序號,無效結點記為2*maxn
}node[maxn];
bool isExist[TABLE]={false};
bool cmp(Node a,Node b){
return a.order<b.order;
}
int main(){
memset(isExist,false,sizeof(isExist));//初始化isExist為未出現
for(int i=0;i<maxn;i++){
node[i].order=2*maxn;
}
int n,begin,address;
scanf("%d%d",&begin,&n);
for(int i=0;i<n;i++){
scanf("%d",&address);
scanf("%d%d",&node[address].data,&node[address].next);
node[address].address=address;
}
//未刪除的有效結點個數和已刪除的有效結點個數
int countValid=0,countRemoved=0,p=begin;
while(p!=-1){
if(!isExist[abs(node[p].data)]){//data的絕對值不存在
isExist[abs(node[p].data)]=true;
node[p].order=countValid++;
}else{
node[p].order=maxn+countRemoved++;
}
p=node[p].next;
}
sort(node,node+maxn,cmp);//將order從小到大排序
//輸出結果
int count=countValid+countRemoved;
for(int i=0;i<count;i++){
if(i!=countValid-1&&i!=count-1){
printf("%05d %d %05d\n",node[i].address,node[i].data,node[i+1].address);
}else{
printf("%05d %d -1\n",node[i].address,node[i].data);
}
}
return 0;
}
總結:不能熟練運用排序的思想,以及排序之後,輸出next域的值要直接輸出下一個元素的address
待改善:還未找出自己程式碼的bug