1133. Splitting A Linked List (25)

来源:互联网 发布:手机淘宝卖东西怎么弄 编辑:程序博客网 时间:2024/05/18 23:28

网上看到一道不错的题目,做了一下感觉对链表的理解有很大的帮助。题目的意思是给定一个正数K和一个链表 ,把链表的节点分成3类输出,先输出负数,再输出小于K的非负数,最后输出大于K的数,每一类输出保持原来的相对顺序不变。

比如给定链表18→7→-4→0→5→-6→10→11→-2K=10,输出-4→-6→-2→7→0→5→10→18→11。正式输入时第一行为首节点地址,节点数和K值,后面每行分别输输入节点的首地址,节点数值,下一节点的地址,输入的时候节点顺序是打乱了的。输出的时候按排好的顺序输出,并且本节点输出的下一节点地址与下一节点输出的地址是相同的,地址按5位数输出,不足5位的前面补0NULL-1表示,格式如下:

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

      一般的做法都是定义一个很大的数组list[100000],用数组的下标来定位下一个节点,在输入节点数量很多的时候,这种做法可以有效提高排序的速度,又不会浪费太多内存。当输入节点比较少的时候,就会有大量内存浪费,本文主要针对这种情况,在节点输入比较少的情况下,直接对链表排序,牺牲一点cpu效率来节省内存空间。具体的选择还要根据实际情况做出折中。

      首先输入的链表是无序的,但是可以根据节点的前后地址进行2层轮询最后得到链表的正确顺序,这里比较费时间,时间复杂度O(n^2),得到正确顺序的链表后就可以直接输出了,分3次遍历链表,将已经输出的节点删除可以减少下一次遍历的时间。

#include <stdio.h>#include <assert.h>struct NODE {    int addr;    int data;    int next_addr;    struct NODE *next_node;};typedef struct NODE NODE;void output_print(NODE* link_node,NODE* pre_node){    static int flag=0;    if(!flag)    {        printf("%05d %d ", link_node->addr,link_node->data);        flag=1;    }    else    {        printf("%05d\n%05d %d ", link_node->addr,link_node->addr,link_node->data);    }    pre_node->next_node = link_node->next_node;//删除输出的节点}void Splitting_A_Linked_List(void){    int nodes_num,first_addr,k;    int first_node_index=0,end_flag=0;    NODE *link_node,*pre_node;    scanf("%d %d %d",&first_addr,&nodes_num,&k);    assert((nodes_num>0) && (nodes_num<=100000));    assert((k>0) && (nodes_num<=1000));    NODE input_node[nodes_num];//变长数组,gcc支持    for(int i=0;i<nodes_num;i++)//输入所有节点    {        scanf("%d %d %d",&input_node[i].addr,&input_node[i].data,&input_node[i].next_addr);        input_node[i].next_node = NULL;        if(input_node[i].addr == first_addr)        {            first_node_index = i;//定位头节点        }        end_flag=0;        for(int j=0;j<i;j++)        {            if(input_node[i].next_addr == input_node[j].addr)//存在之前输入节点的地址等于当前下一节点地址            {                end_flag++;                input_node[i].next_node = &input_node[j] ;//将该节点插入当前节点之后                if(end_flag == 2)  break;            }            if(input_node[i].addr == input_node[j].next_addr)//存在之前输入节点的下一节点地址与当前节点地址相同            {                end_flag++;                input_node[j].next_node = &input_node[i] ;//将当前节点插入该节点之后                if(end_flag == 2)  break;          //前后地址的节点都找到后就可以跳出循环了            }        }    }    for(int i=0;i<3;i++)//分3次轮询链表    {        link_node = &input_node[first_node_index];        pre_node = link_node;        while(link_node!= NULL)        {            switch (i)            {                case 0:                    if(link_node->data<0)                    {                        output_print(link_node,pre_node);                    }                    break;                case 1:                    if(link_node->data>=0 && link_node->data <= k )                    {                        output_print(link_node,pre_node);                    }                    break;                case 2:                    if(link_node->data > k )                    {                        output_print(link_node,pre_node);                    }                    break;                default:                    break;            }            pre_node=link_node; //保存前一个节点,当删除节点时会用到            link_node=link_node->next_node;//遍历下一个节点        }    }    printf("-1\n");}


原创粉丝点击