牛客网一道题以及对我自己屎山代码的反思

发布时间 2023-04-10 23:34:30作者: 针眼画师

做这么个题, 费了大劲, 不是有什么地方不会需要去查, 也不是没思路, 而是纯粹的脑子糊涂。 东一榔头西一棒槌, 把握不住要点,这是做事方式的问题。

这样写代码,绝对是第二天就看不懂的那种

我写的141行屎山
#include <stdio.h>
#include <stdlib.h>

/*
明明生成了N个1到500之间的随机整数。请你删去其中重复的数字,即相同的数字只保留一个,把其余相同的数去掉,然后再
把这些数从小到大排序,按照排好的顺序输出。数据范围: 1≤n≤1000  ,输入的数字大小满足 1≤val≤500 
*/
//第一行先输入随机整数的个数 N 。 接下来的 N 行每行输入一个整数,代表明明生成的随机数。 具体格式可以参考下面的"示例"。
//输出多行,表示输入数据处理后的结果
int main() 
{
	// 变量size用于储存随机数的个数 
    int size;
    // 读取随机数的个数
	scanf("%d",&size);
	// 测试用,输出读取的随机数的个数
	//printf("%d",size); 
    // 数组numbers用于储存输入的随机数
    int * numbers;
	numbers=(int *) malloc(sizeof(int)*size); 
	// 用于储存中间变量和最值的变量max
	int max=0; 
	// 用于储存重复数字的数量n,其他用途的中间变量m 
	int n=0,m=0; 
 
	// 测试用,输出数组的元素个数
	//printf("%d",sizeof(numbers)/sizeof(numbers[0])); 
	// 为数组读取第一个值,用于开启判断;
	scanf("%d",&numbers[0]);
	// 接收随机数的输入,同时判断是否有重复 ,外循环从1开始,因为前面读取了数组的第一个值 
	for (int i=1;i<size;i++)
	{
		// 临时使用max充当中间变量 
		scanf("%d",&max);
		for (int j=0;j<i;j++)
		{
			// 相等意味着重复了,赋值501 
			if (max==numbers[j])
			{
				numbers[i]=501;
				n++; 
				break;
			}
			// 不相等意味着没重复,读值即可 
			else
			{
				numbers[i]=max;
			} 
		}
		
	} 
	// 测试用,输出数组
	for (int i=0;i<size;i++)
	{
		printf("numbers[%d]=%d\n",i,numbers[i]);
	}
	printf("=============\n");
	// 把所有的501放到数组后边,max做中间变量 
	for (int i=0;i<size-n;i++)
	{
		if (numbers[i]==501)
		{
			// 测试用,输出元素位置 
			printf("numbers[%d]=%d\n", i, numbers[i]);
			// 判断后面有无501,不能把后面的501放前面去 
			while (numbers[size-1-m]==501)
			{
				printf("numbers[%d]=%d等于501\n", size - 1 - m, numbers[size - 1 - m]);
				m++;
			}
			// 储存后边的值到max,把501放过去,把后面的值放过来 
			printf("和numbers[%d]=%d交换\n", size - 1 - m, numbers[size - 1 - m]);
			max=numbers[size-1-m];
			numbers[size-1-m]= numbers[i];
			numbers[i]=max;
			// 测试用,输出 numbers[size-1-m]和 numbers[i]
			printf("交换之后\n");
			printf("numbers[%d]=%d\n",i,numbers[i]);
			printf("numbers[%d]=%d\n",size-1-m,numbers[size-1-m]);
			printf("############\n");
			m++;
		}
	} 
	// 测试用,输出数组
	for (int i=0;i<size;i++)
	{
		printf("numbers[%d]=%d\n",i,numbers[i]);
	}
	printf("=============\n");
	// 改变数组的大小
	size=size-n;
	numbers=(int *) realloc(numbers,sizeof(int)*(size)); 
	// 测试用,输出数组
	for (int i=0;i<size;i++)
	{
		printf("numbers[%d]=%d\n",i,numbers[i]);
	}
	printf("=============\n");
	
	// 排大小,max储存大值,m储存对应该值的序号 ,n储存排好的个数 
	n=0;  
	// size-1次循环即可,最后一位不用比,n计数 
	// 两个数字比一次,三个数字比两次..... 
	for (int i=0;i<size-1;i++)
	{
		// 每次都从numbers[0]开始比
		m=0; 
		max=numbers[m];
		// 每排好一个数,下一次就少比一次,用n计数 从1开始 
		for (int j=0;j<size-n;j++)
		{
			// 比max大则成为max,记序号 
			if (max<numbers[j])
			{
				max=numbers[j];
				m=j;
			} 
		} 
		// 完成一次比较,与末位元素交换位置,n++
		printf("max=%d\n",max);
		printf("没换之前末位数位置numbers[%d]=%d\n",size-1-n,numbers[size-1-n]);
		printf("没换之前最大数位置numbers[%d]=%d\n",m,numbers[m]);
		numbers[m]=numbers[size-1-n];
		printf("换了之后最大数位置numbers[%d]=%d\n",m,numbers[m]);
		numbers[size-1-n]=max;
		printf("换了之后末位数位置numbers[%d]=%d\n",size-1-n,numbers[size-1-n]);
		n++; 
	}
	
	// 测试用,输出数组
	for (int i=0;i<size;i++)
	{
		printf("numbers[%d]=%d\n",i,numbers[i]);
	}
	printf("=============\n");
	
	// 释放内存
	free(numbers); 
	
    return 0;
}
去掉测试输出部分后的87行屎山
#include <stdio.h>
#include <stdlib.h>

int main() {
    // 变量size用于储存随机数的个数
    int size;
    // 读取随机数的个数
    scanf("%d", &size);
    // 数组numbers用于储存输入的随机数
    int* numbers;
    numbers = (int*) malloc(sizeof(int) * size);
    // 用于储存中间变量和最值的变量max
    int max = 0;
    // 用于储存重复数字的数量n,其他用途的中间变量m
    int n = 0, m = 0;

    // 为数组读取第一个值,用于开启判断;
    scanf("%d", &numbers[0]);
    // 接收随机数的输入,同时判断是否有重复 ,外循环从1开始,因为前面读取了数组的第一个值
    for (int i = 1; i < size; i++) {
        // 临时使用max充当中间变量
        scanf("%d", &max);
        for (int j = 0; j < i; j++) {
            // 相等意味着重复了,赋值501
            if (max == numbers[j]) {
                numbers[i] = 501;
                n++;
                break;
            }
            // 不相等意味着没重复,读值即可
            else {
                numbers[i] = max;
            }
        }
    }
    // 把所有的501放到数组后边,max做中间变量
    for (int i = 0; i < size - n; i++) {
        if (numbers[i] == 501) {

            // 判断后面有无501,不能把后面的501放前面去
            while (numbers[size - 1 - m] == 501) {
                m++;
            }
            // 储存后边的值到max,把501放过去,把后面的值放过来
            max = numbers[size - 1 - m];
            numbers[size - 1 - m] = numbers[i];
            numbers[i] = max;
            m++;
        }
    }

    // 改变数组的大小
    size = size - n;
    numbers = (int*) realloc(numbers, sizeof(int) * (size));

    // 排大小,max储存大值,m储存对应该值的序号 ,n储存排好的个数
    n = 0;
    // size-1次循环即可,最后一位不用比,n计数
    // 两个数字比一次,三个数字比两次.....
    for (int i = 0; i < size - 1; i++) {
        // 每次都从numbers[0]开始比
        m = 0;
        max = numbers[m];
        // 每排好一个数,下一次就少比一次,用n计数 从1开始
        for (int j = 0; j < size - n; j++) {
            // 比max大则成为max,记序号
            if (max < numbers[j]) {
                max = numbers[j];
                m = j;
            }
        }
        // 完成一次比较,与末位元素交换位置,n++
        numbers[m] = numbers[size - 1 - n];
        numbers[size - 1 - n] = max;
        n++;
    }

    // 输出数组
    for (int i = 0; i < size; i++) {
        printf("%d\n",numbers[i]);
    }

    // 释放内存
    free(numbers);

    return 0;
}

以上面这道题为例, 我重新捋一遍, 看看到底应该怎么做才是合适的做法


首先,看要求,可以分为接收数据、处理数据、输出数据三部分。
数据的输入是每行一个整数数据,因此可以考虑使用scanf()接收数据;使用一个整型变量存储数字的个数,使用一个整数数组存储所有的数字。
数据的输出是每行一个数据,因此可以使用printf()
数据的处理最麻烦:1、要清除重复数字;2、要知道清除重复数字以后的数字个数;3、要给剩余数字排序。

其次就是看怎么实现(按照今天写的思路来)。
一、数据的输入: 使用一个scanf()接收数字个数size;使用一个for()循环,从0size-1,每一次循环使用一次scanf(),将数字存入numbers[i]
二、数据的输出: 使用一个for()循环,从0size-1,这里的size是更新过大小的,以后用size-n表示,每循环一次使用一次printf()
三、清除重复数字: 需要知道哪些位置是重复的,将这些位置用特殊的整数代替即可。借着输入时的for()循环,当读入第i个数字时,后面接一个从0i-1for(j)循环,把numbers[i]numbers[j]进行比较。如果相同,就把这个读入的数字改为501,也就是numbers[i]=501(题目输入数字的范围是1~500),同时计数器n++,然后退出这个循环,读取下一个数字。这样做,在输入完成时,就已经完成了重复数字的初步处理和统计。。。。。。因为我使用动态数组,可以改变数组的大小,所以我考虑将所有的501排在数组的末尾,方便截断。使用一个0size-n-1for()循环,每次循环判断一次if (numbers[i]==501),如果成立,再使用一个size-10for()循环,每次循环判断一次if (numbers[j]!=501),如果成立,交换numbers[i]numbers[j]的值。因为size_new是不包含重复值的个数,所以外层循环虽然小于内层循环,但一定能把501们放到数组的末尾。。。。。。最后使用realloc()重分配数组的内存,也就是把size变成size-n,截断掉后面的501们。
四、知道清除重复数字以后的数字个数: 这是上一步的副产物,并且在上一步已经使用过了。
五、排序: 选择由大到小排序,也就是最大值放最后,次大值放倒数第二位,以此类推。先做一个for()循环,因为是两两比较,并且不使用循环变量,所以这个for()循环是从0size-n-2。每一次循环,都给max赋初值numbers[0],然后再写一个for()循环,从size-n-10,每次循环都判断一次if (max < numbers[j]),如果成立则把numbers[j]保存在max中,并保存numbers[j]所在的位置jm中,也就是m=j;。当内循环进行到j==0时,交换m位置的值和size-n-1-i位置的值。

我按照文字算法写了代码,略加修改就已经可以使用了,而且占用内存更小,运行更快。最重要的是,我不会急于写一坨谢特,然后再一点一点修改,从而浪费大量时间。我了解到有经验的程序员使用程序框图来实现,我现在不会这些,暂时用文字代替,尽快学会使用程序框图。

不要把时间浪费在会的地方上,会却花费大量时间,不应该。

73行新程序
#include <stdio.h>
#include <stdlib.h>
// 
int main() {
    // 变量size用于储存随机数的个数
    int size;
    // 读取随机数的个数
    scanf("%d", &size);
    // 数组numbers用于储存输入的随机数
    int* numbers;
    numbers = (int*) malloc(sizeof(int) * size);
    // 用于储存中间变量和最值的变量max
    int max = 0;
    // 用于储存重复数字的数量n
    int n = 0, m = 0;

    // 接收随机数的输入,同时判断是否有重复 ,外循环从1开始,因为前面读取了数组的第一个值
    for (int i = 0; i < size; i++) {
        // 临时使用max充当中间变量
        scanf("%d", &numbers[i]);
        for (int j = 0; j < i; j++) {
            // 相等意味着重复了,赋值501
            if (numbers[i] == numbers[j]) {
                numbers[i] = 501;
                n++;
                break;
            }
        }
    }
    // 
    for (int i = 0; i < size - n ; i++) {
        if (numbers[i] == 501) {
            for (int j = size - 1; j > 0; j--) {
                if (numbers[j] != 501) {
                    max = numbers[j];
                    numbers[j] = numbers[i];
                    numbers[i] = max;
                }
            }
        }
    }
    // 
    size = size - n;
    numbers = (int*) realloc(numbers, sizeof(int) * (size));
    // 
    // 
    for (int i = 0; i < size - 1; i++) {
        // 
        m=0;
        max = numbers[0];
        // 
        for (int j = size - 1-i ; j >= 0; j--) {
            // 
            if (max < numbers[j]) {
                max = numbers[j];
                m = j;
            }
            if (j == 0) {
                numbers[m] = numbers[size - 1 - i];
                numbers[size - 1 - i] = max;
            }
        }
    }
    // 输出数组
    for (int i = 0; i < size; i++) {
        printf("%d\n", numbers[i]);
    }

    // 释放内存
    free(numbers);

    return 0;
}