A1133. Splitting A Linked List

时间:2023-03-09 03:05:48
A1133. Splitting A Linked List

Given a singly linked list, you are supposed to rearrange its elements so that all the negative values appear before all of the non-negatives, and all the values in [0, K] appear before all those greater than K. The order of the elements inside each class must not be changed. For example, given the list being 18→7→-4→0→5→-6→10→11→-2 and K being 10, you must output -4→-6→-2→7→0→5→10→18→11.

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^5) which is the total number of nodes, and a positive K (≤10^3). 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 in [-10^5, 10^5], and Next is the position of the next node. It is guaranteed that the list is not empty.

Output Specification:

For each case, output in order (from beginning to the end of the list) the resulting linked list. Each node occupies a line, and is printed in the same format as in the input.

Sample Input:

00100 9 10
23333 10 27777
00000 0 99999
00100 18 12309
68237 -6 23333
33218 -4 00000
48652 -2 -1
99999 5 68237
27777 11 48652
12309 7 33218

Sample Output:

33218 -4 68237
68237 -6 48652
48652 -2 12309
12309 7 00000
00000 0 99999
99999 5 23333
23333 10 00100
00100 18 27777
27777 11 -1
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef struct NODE{
int data, addr, next, valid, greater, neg, rank;
NODE(){
valid = ;
}
}node;
node list[];
int first, N, K;
bool cmp(node a, node b){
if(a.valid != b.valid){
return a.valid > b.valid;
}else{
if(a.neg != b.neg)
return a.neg > b.neg;
else{
if(a.greater != b.greater)
return a.greater < b.greater;
else return a.rank < b.rank;
}
}
}
int main(){
scanf("%d%d%d", &first, &N, &K);
for(int i = ; i < N; i++){
int addr, data, next;
scanf("%d%d%d", &addr, &data, &next);
list[addr].addr = addr;
list[addr].data = data;
list[addr].next = next;
if(data <= K)
list[addr].greater = ;
else list[addr].greater = ;
if(data < )
list[addr].neg = ;
else list[addr].neg = ;
}
int cnt = , pt = first;
while(pt != -){
list[pt].valid = ;
list[pt].rank = cnt;
pt = list[pt].next;
cnt++;
}
sort(list, list + , cmp);
for(int i = ; i < cnt - ; i++){
list[i].next = list[i+].addr;
printf("%05d %d %05d\n", list[i].addr, list[i].data, list[i].next);
}
printf("%05d %d -1\n", list[cnt - ].addr, list[cnt-].data);
cin >> N;
return ;
}

总结: 1、题意:将链表重新排序,要求负数在前,正数在后;同时给出一个正数K,要求小于等于K的数在前,大于K的数在后。至于没有先后关系的数,保持它们在原链表中的先后顺序(注意原链表的顺序不是输入顺序,而是遍历一边之后得到的节点顺序)。 2、做法是使用静态链表,先遍历一遍链表,标注出合法节点。再进行排序,按照合法节点在前,非法节点在后;合法节点中,负数在前;同正负的,小于等于K的数在前。排序后发现似乎不是稳定排序,只好在之前遍历的时候加入一个rank记录每个节点的原始顺序,当两节点之间需要保持原始顺序时使用。 3、在网上还看到一种做法更简便:将所有数分成(负无穷,0),[0,K], (K, 正无穷]三个区间,将不同段的节点依次放入结果数组中即可。