C++程序 区间查询数组元素频率

C++程序 区间查询数组元素频率

在数学和计算机科学中,数组是一种数据结构,由一组固定大小的相同类型的元素组成。数组中的元素使用索引访问,索引通常是整数。在实际的编程应用中,数组被广泛用于存储和处理数据。在本篇文章中,我们将探讨如何使用C++编程实现区间查询数组元素频率,并结合示例代码进行讲解。

数组的频率查询

在数组中,一个元素的频率指的是该元素在数组中出现的次数。频率查询常常用于统计数据分布情况,识别异常数据等。对于一个长度为n的数组,我们可以使用简单的算法对其元素的频率进行计算,如下所示:

#include <iostream>

using namespace std;

int main()
{
    int n, a[100], freq[100];

    cout << "Enter the size of the array: ";
    cin >> n;

    cout << "Enter the elements: ";
    for(int i=0; i<n; i++)
    {
        cin >> a[i];
        freq[i] = -1;
    }

    for(int i=0; i<n; i++)
    {
        int count = 1;
        for(int j=i+1; j<n; j++)
        {
            if(a[i] == a[j])
            {
                count++;

                freq[j] = 0;
            }
        }

        if(freq[i] != 0)
        {
            freq[i] = count;
        }
    }

    cout << "Frequency of all the elements in the array: " << endl;
    for(int i=0; i<n; i++)
    {
        if(freq[i] != 0)
        {
            cout << a[i] << " occurs " << freq[i] << " times." << endl;
        }
    }

    return 0;
}

以上代码中,我们首先输入数组的大小和元素,然后使用两个for循环对其元素的频率进行计算。具体地,外层循环遍历数组中的每个元素,内层循环计算该元素在数组中出现的次数,并将该元素在数组中的所有出现位置标记为0。最后,我们输出数组中所有元素的频率。

区间查询数组元素频率

上面介绍的算法计算了整个数组中元素的频率,但在实际应用中,我们通常需要计算数组中某个区间内元素的频率。例如,对于一个长度为n的数组,查询其第i个元素到第j个元素之间的所有元素的频率。针对这个问题,我们可以使用线段树来进行优化。

线段树是一种常用的数据结构,用于高效地实现区间查询和更新操作。它是一颗二叉树,每个节点对应着一个区间。对于每个节点,其左儿子表示区间的左半段,右儿子表示区间的右半段,节点本身存储了整个区间的信息,如区间和、区间最大值、区间最小值等。为了方便起见,我们在本文中使用线段树来实现区间查询一个区间内的所有元素的频率。

首先,我们需要编写一个用于构建线段树的函数:

void buildTree(int node, int start, int end, int a[], int tree[], int lazy[])
{
    if(start == end)
    {
        tree[node] = a[start];
        return;
    }

    int mid = (start + end) / 2;
    buildTree(2*node, start, mid, a, tree, lazy);
    buildTree(2*node+1, mid+1, end, a, tree, lazy);

    tree[node] = tree[2*node] + tree[2*node+1];
}

以上代码中,我们使用递归方式建立线段树。具体地,我们传入五个参数:节点编号node、当前区间的起始下标start和结束下标end、原数组a、线段树数组tree、及懒惰标记数组lazy。当我们遍历到叶子节点时,将该节点的值设为原数组该位置上的元素值。

接下来,我们需要编写一个用于查询区间元素频率的函数:

void queryFrequency(int node, int start, int end, int l, int r, int a[], int tree[], int freq[])
{
    if(lazy[node] != 0)
    {
        tree[node] += lazy[node] * (end - start + 1);
        if(start != end)
        {
            lazy[2*node] += lazy[node];
            lazy[2*node+1] += lazy[node];
        }
        lazy[node] = 0;
    }

    if(start > r || end < l)
        return;
    if(start >= l && end <= r)
    {
        for(int i=start; i<=end; i++)
        {
            freq[a[i]]++;
        }
        return;
    }

    int mid = (start + end) / 2;
    queryFrequency(2*node, start, mid, l, r, a, tree, freq);
    queryFrequency(2*node+1, mid+1, end, l, r, a, tree, freq);

    return;
}

以上代码中,我们使用递归方式遍历线段树来查询区间内元素的频率。具体地,我们传入八个参数:节点编号node、当前区间的起始下标start和结束下标end、查询区间l和r、原数组a、线段树数组tree、及频率数组freq。在遍历过程中,我们首先通过懒惰标记更新线段树节点的值,然后根据查询区间与当前区间的关系进行分支。当当前区间完全包含查询区间时,我们遍历该区间内的所有元素,将其频率累加到相应的元素在频率数组中的位置上。当当前区间与查询区间有交集时,我们递归处理其左右两个子区间。

最后,我们将以上两个函数进行合并,编写一个完整的C++程序实现区间查询数组元素频率:

#include <iostream>

using namespace std;

void buildTree(int node, int start, int end, int a[], int tree[], int lazy[])
{
    if(start == end)
    {
        tree[node] = a[start];
        return;
    }

    int mid = (start + end) / 2;
    buildTree(2*node, start, mid, a, tree, lazy);
    buildTree(2*node+1, mid+1, end, a, tree, lazy);

    tree[node] = tree[2*node] + tree[2*node+1];
}

void queryFrequency(int node, int start, int end, int l, int r, int a[], int tree[], int freq[], int lazy[])
{
    if(lazy[node] != 0)
    {
        tree[node] += lazy[node] * (end - start + 1);
        if(start != end)
        {
            lazy[2*node] += lazy[node];
            lazy[2*node+1] += lazy[node];
        }
        lazy[node] = 0;
    }

    if(start > r || end < l)
        return;
    if(start >= l && end <= r)
    {
        for(int i=start; i<=end; i++)
        {
            freq[a[i]]++;
        }
        return;
    }

    int mid = (start + end) / 2;
    queryFrequency(2*node, start, mid, l, r, a, tree, freq, lazy);
    queryFrequency(2*node+1, mid+1, end, l, r, a, tree, freq, lazy);

    return;
}

int main()
{
    int n, a[100], tree[400], lazy[400] = {0};

    cout << "Enter the size of the array: ";
    cin >> n;

    cout << "Enter the elements: ";
    for(int i=0; i<n; i++)
    {
        cin >> a[i];
    }

    buildTree(1, 0,n-1, a, tree, lazy);

    int l, r;

    cout << "Enter the left and right indices of the query interval: ";
    cin >> l >> r;

    int freq[100] = {0};
    queryFrequency(1, 0, n-1, l, r, a, tree, freq, lazy);

    cout << "Frequency of elements in the interval [" << l << ", " << r << "]: " << endl;
    for(int i=0; i<100; i++)
    {
        if(freq[i] != 0)
        {
            cout << i << " occurs " << freq[i] << " times." << endl;
        }
    }

    return 0;
}

以上代码中,我们首先输入数组的大小和元素,然后使用buildTree函数建立线段树。接着,我们输入查询区间的左右下标,并使用queryFrequency函数查询该区间内元素的频率,最后输出查询结果。

结论

在本篇文章中,我们通过使用C++编程示例,讲解了如何计算数组中元素的频率,并使用线段树优化了区间查询数组元素频率的算法。通过这些代码示例,读者可以更好地掌握如何使用C++来实现该功能,对于算法设计和程序思维的培养也有很大的帮助。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程

C++ 示例