• 用数组解决问题(一)


    由于数组在编程中极为常见,并且数组技巧在非数组场合下也常常被使用,因此数组可以作为用数据结构解决问题的重要练兵场所。

    一、基础知识概述

    1,存储

    这是最基本的操作。数组是一组变量的集合,我们可以对其中的每个变量进行赋值。

    tenIntegerArray[0] = 5;  //把整数5赋值给前面所声明的数组的第1个元素 
    int tenIntegerArray[10] = {1,2,3,6,12,-57,30987,0,-287,9};  //给数组中的每个元素赋一个特定的值 
    int tenIntegerArray[10];
    for(int i = 0;i < 10;i++)
        tenIntegerArray[i] = -1;  //把一个数组的10个元素都初始化为-1 

    2,复制

    复制一个数组,只需要使用一个循环和一条赋值语句,就像初始化数值一样。

    int tenIntegerArray[10] = {1,2,3,6,12,-57,30987,0,-287,9};
    int secondArray[10];
    for(int i = 0;i < 10;i++)
        secondArray[i] = tenIntegerArray[i];

    3,提取和搜索

    除了能够把值放入数组中之外,我们还需要能够把它们从数组中提取出来。

    int num = tenIntegerArray[0];

    但通常情况下并没有这么简单。我们常常不知道所需要的位置,必须通过对数组进行搜索才能找到一个特定值的位置。如果数组中的元素并没有特定的顺序,最好执行线性搜索,即从数组的一端开始查看每个元素,直到找到所需要的值。

    const int ARRAY_SIZE = 10;  //数组长度 
    int intArray[ARRAY_SIZE] = {4,5,9,12,-4,0,-57,30987,-287,1};  //数组本身 
    int targeValue = 12;  //在数组中所找到的值
    int targePos = 0;  //所找到的值的位置 
    while((intArray[targetPos] != targeValue)&&(targePos < ARRAY_SIZE))  //使用ARRAY_SIZE常量限制这个数组的迭代次数 
        targePos++;

    有时候,我们所搜索的并不是一个固定的值,而是一个与数组中的其他值存在关系的值。

    例如,我们可能想要在数组中搜索最大值。我把完成这个任务的机制称为“山丘之王”,用一个变量表示数组到目前为止所找到的最大值。用一个循环遍历数组中的所有元素,每当遇到一个比当前最大值更大的值时,就把以前的国王从山丘上踢下去并取而代之:

    const int ARRAY_SIZE = 10;  //数组长度 
    int intArray[ARRAY_SIZE] = {4,5,9,12,-4,0,-57,30987,-287,1};  //数组本身 
    int highestValue = intArray[0];  //在声明之时,它被赋值为数组中的第一个元素的值 
    for(int i = 1;i < ARRAY_SIZE;i++){  //从数组的第二个元素开始循环 
        if(intArray[i] > highestValue)  //把当前位置的值与highestValue进行比较 
            highestValue = intArray[i];  //适时替换highestValue的值 

    4,排序

    按特定的顺序排列数据。

    用qsort进行快速方便的排序

    为了使用qsort,必须编写一个比较函数。这个函数被qsort函数调用,用于比较数组中的两个元素,判断哪个应该出现在排序序列中的更前面。这个函数应该返回一个整数,根据第一个元素是大于、小于或等于第二个元素,这个整数的值分别为正数、负数或零。具体返回的值无关紧要,重要的是它是大于、小于还是等于零。现在,我们通过采用qsort对一个包含10个整数的数组进行排序的简单例子来说明这种排序方法。先写出比较函数:

        int compareFunc(const void * voidA,const void * voidB){
            int * intA = (int *)(voidA);
            int * intA = (int *)(voidB);
            return *intA - *intB;
        }

    有了比较函数之后,下面是qsort的一个示例用法:

        const int ARRAY_SIZE = 10;
        int intArray[ARRAY_SIZE] = {87,28,100,78,84,98,75,70,81,68};
        qsort(intArray,ARRAY_SIZE,sizeof(int),compareFunc);

    但在有些情况下,需要自己编写排序代码。

    我建议是使用一种插入排序算法。它的工作方式与人们在打桥牌时所使用的理牌方式相似:一次抓起一张牌,把它插入到手里这把牌中的适当位置以维持整体的顺序,并移动其余的牌以留出空间。

    以下是整数数组的插入排序算法的基本实现:

    int start = 0;  //数组中的第一个元素 
    int end = ARRAY_SIZE - 1;  //数组中的最后一个元素 
    for(int i = start + 1;i <= end;i++){  //外层循环选择下一张需要插入的牌,它被插入到当前按升序排列的一把牌中 
        for(int j = i;j > start&&intArray[j-1] > intArray[j];j--){  //不断地把当前值与它的前一个值进行交换,直到它到达正确的位置 
            int temp = intArray[j-1];  //把当前值交换到数组中的前一个位置 
            intArray[j-1] = intArray[j];
            intArray[j] = temp;
        }
    }

    5,计算统计数据

    与提取操作相似。区别在于它是根据数组中的所有值进行计算所产生的统计数据。例如计算一组学生成绩的平均值:

        const int ARRAY_SIZE = 10;
        int gradeArray[ARRAY_SIZE] = {87,76,100,97,64,83,88,92,74,95};
        double sum = 0;
        for(int i = 0;i < ARRAY_SIZE;i++)
            sum += gradeArray[i];
        double arerage = sum / ARRAY_SIZE;

    另一个简单例子就是数据验证。假设有一个称为vendorPayments的包含double值的数组,表示向销售商的支付情况。

    二、用数组解决问题

    问题:寻找众数

    在统计学中,一组值的众数就是最常出现的值。编写代码,处理一个包含了调查数据的数组,确定这个数据集的众数。在这个数组中,接受调查者用1~10范围内的一个数表示一个问题的答案。对于我们而言,如果存在多个众数,可以任选其一。

    1,我们首先观察这个问题的一个示例数组以及它的长度常量:

        const int ARRAY_SIZE = 12;
        int surveyData[ARRAY_SIZE] = {4,7,3,8,9,7,3,9,9,3,3,10};

    简化后:

        int surveyData[ARRAY_SIZE] = {4,7,7,9,9,9,8,3,3,3,3,10};

    现在,2个7出现在一起,3个9也是如此,所有的3也都几张在一起。当数据按照这种方式排列之后,我们就能够线性地处理这个数组并找到众数了。

    2,我们先编写一些伪码:(所谓伪码,就是与程序代码相似的语句,它可以提醒我们在编写每条语句时应该要完成什么任务)

        int mostFrequent = ?;
        int highestFrequency = ?;
        int currentFrequency = 0;
        for(int i = 0;i < ARRAY_SIZE;i++){  //处理数组 
            currentFrequency++;  //对当前值的出现次数进行计数的变量的值加1 
            if(surveyData[i] is last occurrence of a value){  //检查,观察是否到达了一个特定值的最后一次出现 
                if(currentFrequency > highestFrequency){  //如果是,这个值就成为新的最常见的值 
                    highestFrequency = currentFrequency;
                    mostFrequent = surveyData[i];
                }
                currentFrequency = 0;  //由于下一个被读取的值将是新值的第一次出现,因此我们把计数器重置为0 
            }
        }

    ,3,我们回到前面暂时跳过的if语句的逻辑。

    怎么才能知道一个值在数组中最后一次出现呢?

    由于数组中的值已经分组,因此当数组中的下一个值与当前值不同时(surveyData[i] 不等于 surveyData[i+1]),我们就知道现在是当前值的最后一次出现。

    4,现在可以考虑变量初始值的问题。

    现在,“当前的最常见”值用2个变量表示,mostFrequent表示值本身,highestFrequency表示它的出现次数。如果能把mostFrequent初始化为数组中所出现的第一个值并把highestFrequency初始化为这个值在数组中的出现次数当然是最好不过了,但在进入循环并开始计数之前,还没有办法确定第一个值的出现次数。此时,我们可能会想到,不管第一个值的出现次数是多少,它总是大于零。因此,我们把highestFrequency变量值初始化为零。当我们到达第一个值的最后一次出现时,这段代码就会把highestFrequency变量的值替换为第一个值的出现次数。完整代码如下:

        int mostFrequent;
        int highestFrequency = 0;
        int currentFrequency = 0;
        for(int i = 0;i < ARRAY_SIZE;i++){  
            currentFrequency++;  
            //if(surveyData[i] is last occurrence of a value)
            if(i == ARRAY_SIZE - 1 || surveyData[i] != surveyData[i+1]){  
                if(currentFrequency > highestFrequency){   
                    highestFrequency = currentFrequency;
                    mostFrequent = surveyData[i];
                }
                currentFrequency = 0;  
            }
        }

    对数组进行排序的问题,我们只要在代码开始时调用qsort就可以了:

        qosrt(surveyData,ARRAY_SIZE,sizeof(int),comareFunc);

     5,重构

    是不是存在这样一个数组,我们可以对它应用“寻找最大值”方法,从而得到调查数据的众数?答案是肯定的。

    我们所需要的数组是surveyData数组的柱状图。柱状图就是显示在底层数据中的不同数据的出现频率的图形。我们所需要的数组就是表示这种柱状图的数据。换句话说,我们将在一个长度为10个元素的数组中存储1到10的每个值在surveyData数组中的出现频率。以下是创建柱状图的代码:

        const int MAX_RESPONSE = 10;
        int histogram[MAX _RESPONSE];  //保存柱状图数据的数组 
        for(int i = 0;i < MAX_RESPONSE;i++){  //把数组的每个值初始化为0 
            histogram[i] = 0;
        }
        for(int i = 0;i < ARRAY_SIZE;i++){  //对surveyData数组中的每个值的出现次数进行计数 
            histogram[surveyData[i] - 1]++;
        }

    (注意:柱状图代码是独立编写的,这样就可以对它进行单独的测试。)

    对上面的代码进行了测试之后,现在就可以搜索histogram数组的最大值了:

        int mostFrequent = 0;  //初始化 
        for(int i = 1;i < MAX_RESPONSE;i++){
            if(histogram[i] > histogram[mostFrequent])
                mostFrequent = i;
        }
        mostFrequent++;

    注意:mostFrequent将是histogram数组中最大值的位置,而不是最大值本身。  因此,我们把它初始化为0而不是location[0]的值;在if语句中,我们把它与histogram[mostFrequent]进行比较,而不是与mostFrequent本身进行比较。在找到一个更大值时,我们把mostFrequent赋值为1而不是histogram[i]。最后,我们把mostFrequent的值增加1,这正好与前一个循环中减去1得到正确的数组位置的操作相反。例如,如果把mostFrequent告诉我们最大的数组位置是5,表示调查数据中最常出现的项是6。

    总结

    柱状图解决方案的复杂度随着SurveyData数组的元素数量增加而线性增长,这也是我们能够期待的最好结果了。因此,相比原来的排序方法,它是更好的解决方案。

  • 相关阅读:
    三步搭建精准召回体系,挽回流失用户
    HMS Core Insights第二期直播预告——华为定位技术让你重拾方向感
    如何区分router.push跳转快应用的来源渠道
    华为预测服务的构建原理是什么?该如何训练模型?
    HarmonyOS开发者日干货资料,奉上!
    技术硬核、体验新颖……HarmonyOS开发者日最值得关注的点都在这里
    Js中Proxy对象
    迭代器模式
    ed命令
    百度实习生前端面试面经
  • 原文地址:https://www.cnblogs.com/OctoptusLian/p/6345622.html
Copyright © 2020-2023  润新知