三天前偶尔在一个群里看到个妹子很费力的提问,我这种助妹子为乐的好人自然是要跑去凑合下的,于是很偶然的做了人参第一刀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;
}