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 = 0; } }node; node list[100001]; 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 = 0; 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 = 0; else list[addr].greater = 1; if(data < 0) list[addr].neg = 1; else list[addr].neg = 0; } int cnt = 0, pt = first; while(pt != -1){ list[pt].valid = 1; list[pt].rank = cnt; pt = list[pt].next; cnt++; } sort(list, list + 100000, cmp); for(int i = 0; i < cnt - 1; i++){ list[i].next = list[i+1].addr; printf("%05d %d %05d\n", list[i].addr, list[i].data, list[i].next); } printf("%05d %d -1\n", list[cnt - 1].addr, list[cnt-1].data); cin >> N; return 0; }
总结:
1、题意:将链表重新排序,要求负数在前,正数在后;同时给出一个正数K,要求小于等于K的数在前,大于K的数在后。至于没有先后关系的数,保持它们在原链表中的先后顺序(注意原链表的顺序不是输入顺序,而是遍历一边之后得到的节点顺序)。
2、做法是使用静态链表,先遍历一遍链表,标注出合法节点。再进行排序,按照合法节点在前,非法节点在后;合法节点中,负数在前;同正负的,小于等于K的数在前。排序后发现似乎不是稳定排序,只好在之前遍历的时候加入一个rank记录每个节点的原始顺序,当两节点之间需要保持原始顺序时使用。
3、在网上还看到一种做法更简便:将所有数分成(负无穷,0),[0,K], (K, 正无穷]三个区间,将不同段的节点依次放入结果数组中即可。