行数据的排序

三天前偶尔在一个群里看到个妹子很费力的提问,我这种助妹子为乐的好人自然是要跑去凑合下的,于是很偶然的做了人参第一刀ACM题。

大学贪玩,毕业工作了慢慢才开始有所积累,基础自然是很薄弱的。之前对这些题不怎么感兴趣,对所谓算法什么的重要性没有切身体会。整花了三天功夫费九牛二虎之力最后总算做出来,结果提交到自动判题系统还被报超时,和其他人的记录比起来代码也是臃肿的惊人。

对这个在线测试系统的原理不太了解,暂时也不深究这道题了。

不过过程中收获颇丰,因此也新开了一栏,以后做过的类似练习题都记于此。

 

题目:行数据的排序 

Time Limit:1000MS Memory Limit:30000KB

Description
有N行数据,每行有若干数量不等的整数组成。现在要对这N行数据排序。排序原则为:首先比较行中的第一个数的值,将第一
个数大的行排在前面;若第一个数相等的话,则按照第二个数的值排序(若某行没有第二个数,则该行排在后面);若第二个
数还是相等的话,则比较第三个数,依次类推。
例如:
14 38 11 89
27 34
27 12 34
27
92 2 3 1
17 2
排序的结果为:
92 2 3 1
27 34
27 12 34
27
17 2
14 38 11 89

 

Input
第1行:整数T(1≤T≤10)为问题数
第2行:第一个问题的整数N(1≤N≤1000)
第3 ∽ N+2行:第一个问题的每行的数据ai和表示行结束的标志-1, 1≤数据个数≤50。0≤ai≤10^9, 数据之间由一个空格分隔。
后面是第2 ∽ T个问题的数据。格式与第一个问题相同。

 

Output
对于每个问题,输出排序后的结果。
格式为:每行输出一行数据,数据之间有一个空格。

 

Sample Input
2
6
14 38 11 89 -1
27 34 -1
27 12 34 -1
27 -1
92 2 3 1 -1
17 2 -1
1
1 -1

 

Sample Output
92 2 3 1
27 34
27 12 34
27
17 2
14 38 11 89
1


以下是我自己写出来的第一份代码

可以看到代码风格比较混乱,链表是自己实现的,而栈就直接用了标准库容器。

malloc类函数均未free处理,这种事不常做还是很容易忘的。

功能上暂时是认为通过了,性能上的欠缺以后有空再研究,这个因为没有标准参考答案和标准测试用例,弄起来比较麻烦。

过程中犯了很多错误,也深深体会到了数据结构的重要,假如事先不知道链表、栈等就没法解决。


#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <math.h>
#include <conio.h>

using namespace std;

typedef struct NODE_TYP
{
	int data;
	NODE_TYP *next;
}NODE,*NODE_PTR;

typedef struct LIST
{
	NODE_PTR head;
	NODE_PTR tail;
}LIST,*LIST_PTR;

void insert_list( int data,LIST_PTR plist)
{
	if(plist->tail == NULL)
	{
		(plist)->head->data = data; 
		(plist)->head->next = NULL;
		(plist)->tail = (plist)->head;
	}
	else
	{
		NODE_PTR new_node = (NODE_PTR)malloc(sizeof(NODE));
		new_node->data = data;
		new_node->next = NULL;
		(plist)->tail->next = new_node;
		(plist)->tail = new_node;
	}
}

int LessThan(NODE_PTR list,NODE_PTR list_next)
{
	if( list->data < list_next->data)
		return 1; 
	else if(( list->data == list_next->data)&&(list_next->next != NULL))
		{
			if(list->next == NULL)
				return 1;
			else
				LessThan(list->next,list_next->next);
		}
		else return 0;
}

void print_plist(NODE_PTR plist)
{
	NODE_PTR p;
	p = plist;
	while( p != NULL)
	{
		printf("%d ",p->data);
		p = p->next;
	}
	printf("\n");
}

//为简化设计:1,输入均假定为正确格式,不作错误判断 2,malloc等函数不做错误处理。
int main(void)
{
	int T;
	scanf_s("%d",&T);

	typedef struct RESULT
	{
		LIST_PTR list_array;
		int N;
	}RESULT, *RESULT_PTR;

	RESULT_PTR result = (RESULT_PTR)calloc(T,sizeof(RESULT));

	for(int t=0;t<T;t++)
	{
		int N;
		scanf_s("%d",&N);
		fflush(stdin);//清空缓冲区避免scanf()遗留数据自动激发gets
		LIST_PTR list_array = (LIST_PTR)calloc(N,sizeof(LIST));//模拟一个存放链表结构的数组list_array[N]
		//将每个链表的头节点数据置0,tail = NULL表示节点为空
		for(int i=0;i<N;i++)
		{
			(list_array[i]).head = (NODE_PTR)calloc(1,sizeof(NODE));
			((list_array[i]).head)->data = 0;
			(list_array[i]).tail = NULL;
		}
		//填充各链表
		for(int i=0;i<N;i++)
		{
			char s[500] = {0};
			gets(s);
			stack<int> mystack;

			int count = 0;//统计每个数值的位数,方便计算数值
			int num = 0;//数值

			for(int j=0;j<500;j++)
			{
				//仅以-1的负号做行结束判断,对意外输入不作考虑
				if((s[j] != ' ')&&(s[j] != '-'))
				{
					mystack.push((int)s[j] - 48);
					count++;
				}
				else
				{
					if(count > 0)
					{
						for(int k=0;k<count;k++)
						{
							num += mystack.top()*(int)pow(10.0,k);
							mystack.pop();
						}
						insert_list(num,&list_array[i]);
						count = 0;
						num =0;
					}
				}
				if(s[j] == '-') break;
			}
		}
		//对链表数组排序
		for(int i=0;i<N-1;i++)
		{
			for(int j=0;j<N-i-1;j++)
			{
				//LIST结构tail成员被抛弃,不影响功能
				if(LessThan(list_array[j].head,list_array[j+1].head))
				{
					LIST pTemp = list_array[j];
					list_array[j] = list_array[j+1];
					list_array[j+1] = pTemp;
				}	
			}
		}
		//存储第t批结果
		(result[t]).list_array = list_array;
		(result[t]).N = N; 
	}
	//输出各链表
	for(int t=0;t<T;t++)
	{
		for(int n=0;n<(result[t]).N;n++)
			print_plist((((result[t]).list_array)[n]).head);
	}
}

 

需要注意的点:

1,成员操作符和指向成员操作符的具体含义。

之前对结构体里头的.和->符号一直没怎么弄清。.号可用于结构体引用成员,而->是用于指向结构体的指针引用结构体成员。一个给结构体用,一个给指针用。

2,千万注意函数传递参数方式。

假如希望在子函数中对变量进行操作并保留结果,最好是按引用传递,用指针或引用都行。否则因为函数操作的是实际参数的备份,极易造成某种假象,典型如在函数里互换值了实际退出函数后发现没换。

3,当需要定义长度未知的数组时,可用malloc系列函数模拟,记得free。

4,给指针加下标的具体含义。

p[i] 等同于 *(p+i)。

注意这里是没加括号的,在某些时候比如p是指向结构体数组的指针 p[i].a = 0;会出错,因为.优先级高于*,所以必须加括号 (p[i]).a = 0;

5,scanf()和gets()极易发生冲突。

scanf()遗留下的数据会自动激发gets()产生意外。所以要用fflush(stdin);清空缓冲区。


2014.3.30

上面这个我自己实现的程序,为了节省一点内存空间,用链表,实在是有点二。

下面贴个标准参考答案,直接用数组和标准库排序算法,较简单。

#include <stdio.h>
#include <stdlib.h>
 
#define N 1003
#define L 53
 
int num[N][L];
 
int cmp( const void *a, const void *b ) 
{
    int *x = (int*)a;
    int *y = (int*)b;
    int i;
    for ( i=0; (-1!=x[i])&&(-1!=y[i]); ++i ) 
    {
        if ( x[i] > y[i]) 
        {
            return -1;
        }
        if ( x[i] < y[i]) 
        {
            return 1;
        }
    }
    if ( (-1 == x[i]) && (-1 == y[i])) 
    {
        return 0;
    }
    if ( -1 == y[i]) 
    {
         return -1;
    }
    return 1;
}
 
int main() 
{
    int t,n,a,i,j;
    scanf("%d",&t);
    while (t-- > 0) 
    {
        scanf( "%d", &n );
        for ( i = 0; i < n; ++i ) 
        {
            a = 1;
            for ( j = 0; -1 != a; ++j ) 
	    {
                scanf( "%d", &a );
                num[ i ][ j ] = a;
            }
        }

        qsort( num, n, sizeof(num[0]), cmp );

        for ( i = 0; i < n; ++i ) 
        {
            if ( -1 != num[ i ][ 0 ] ) 
            {
                printf( "%d", num[ i ][ 0 ] );
                for ( j = 1; num[ i ][ j ] != -1; ++j ) 
                {
                    printf( " %d", num[ i ][ j ] );
                }
            }
            printf( "\n" );
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值