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
", list[i].addr, list[i].data, list[i].next);
    }
    printf("%05d %d -1
", list[cnt - 1].addr, list[cnt-1].data);
    cin >> N;
    return 0;
}
View Code

总结:

1、题意:将链表重新排序,要求负数在前,正数在后;同时给出一个正数K,要求小于等于K的数在前,大于K的数在后。至于没有先后关系的数,保持它们在原链表中的先后顺序(注意原链表的顺序不是输入顺序,而是遍历一边之后得到的节点顺序)。

2、做法是使用静态链表,先遍历一遍链表,标注出合法节点。再进行排序,按照合法节点在前,非法节点在后;合法节点中,负数在前;同正负的,小于等于K的数在前。排序后发现似乎不是稳定排序,只好在之前遍历的时候加入一个rank记录每个节点的原始顺序,当两节点之间需要保持原始顺序时使用。

3、在网上还看到一种做法更简便:将所有数分成(负无穷,0),[0,K], (K, 正无穷]三个区间,将不同段的节点依次放入结果数组中即可。
原文地址:https://www.cnblogs.com/zhuqiwei-blog/p/9553756.html