查找计数排序的起始索引

Finding the beginning index for counting sort

本文关键字:索引 排序 查找      更新时间:2023-10-16
int schoolToIndex(string school) {
    if (school == "UCB")  return 0;
    if (school == "UCD")  return 1;
    if (school == "UCI")  return 2;
    if (school == "UCLA") return 3;
    if (school == "UCM")  return 4;
    if (school == "UCSD") return 5;
    if (school == "UCSF") return 6;
    cerr << "Unknown school " << school << endl;
    return -1;
}

void sortByGroupById2(Student students[], int len) {
    int numberofschools = 7;
    int counters[numberofschools];
    for (int i = 0; i < numberofschools; i++) {
        counters[i] = 0;
    }
    for (int i = 0; i < numberofschools; i++) {
        counters[schoolToIndex(students[i].getSchool())]++;
    }
    Student *sortedArray = new Student[len];
    for (int i = 0; i < len; i++) {
    sortedArray[counters[schoolToIndex(students[i].getSchool())]] = students[i];
    counters[schoolToIndex(students[i].getSchool())]++;
    }
    for (int i = 0; i < len; i++) {
        students[i] = sortedArray[i];
    }
}
int main() {
    const int LEN = 350000;
    // Rough timing
    Student* uc2 = readStudentsFromFile("uc_students_sorted_by_id.txt", LEN);
    time(&start);
    sortByGroupById2(uc2, LEN);
    time(&end);
    cout << "Using counting sort it took " << difftime(end, start) << " seconds." << endl;
    writeStudentsToFile(uc1, LEN, "uc_by_school_by_id1.txt");
    writeStudentsToFile(uc2, LEN, "uc_by_school_by_id2.txt");
    return 0;
}

我有问题的具体问题在代码中

 sortedArray[counters[schoolToIndex(students[i].getSchool())]] = students[i],

我的起始指数sortedArray学校的学生人数。我不确定该怎么做的是让开始指数是以前学校的累计学生人数。

例如,如果我想要加州大学洛杉矶分校的起始索引,我需要添加UCB和ucd和UCI的学生人数,以获得此存储桶的起始索引。

所以我的行动计划是让计数器数组来存储学生人数的组合值。例如,如果我的计数器数组将 [5, 10, 15, 20] 作为学生人数,我希望它将 [5, 15, 30, 50] 存储为我的 sortedArray 的起始索引数组。

有什么方法可以用于此吗?我使用递归吗?

计数排序的一部分是将counters[]数组从简单的直方图转换为索引到sortedArray[]的转换。

为此,您可以使用称为部分和的算法。

对于每个元素,使其等于所有先前元素加上该元素的总和。例如:

0 1 3 0 4 0   -->    0 1 4 4 7 7

(您可以手动执行此操作,也可以使用 <numeric> 中的 std::partial_sum() 函数。

现在,您可以使用索引将内容移动到输出中的最终位置。为了保持稳定,请从students[]中的最后一个元素开始,然后在直方图输出索引数组中查找它。

从值中减去 1(修改输出索引(并将源元素复制到最终数组:

for (int i = len; i-->0; )
{
    sortedArray[ --counters[ students[i].getSchool() ] ] = students[i];
}

希望这有帮助。

对于起始索引数组,您可能希望得到的是 [0,5,15,30](请注意,不使用最后一个计数 20(。您可以使计数器 1 个元素更大来执行此操作,也可以使用两个计数变量。计数需要扫描所有学生,这是镜头,而不仅仅是学校数量。

使用两个临时变量,总和 CNT:

    for (int i = 0; i < len; i++) {
        counters[schoolToIndex(students[i].getSchool())]++;
    }
    sum = 0;
    for (int i = 0; i < numberofschools; i++) {
        cnt = counters[schoolToIndex(students[i].getSchool())];
        counters[schoolToIndex(students[i].getSchool())] = sum;
        sum += cnt;
    }

如果将计数器放大一个:

    int counters[numberofschools+1];
    // ...
    for (int i = 0; i <= numberofschools; i++) {
        counters[i] = 0;
    }
    for (int i = 0; i < len; i++) {
        // note the [1 + ...] only used here, not later in the actual sort
        counters[1+schoolToIndex(students[i].getSchool())]++;
    }
    for (int i = 2; i <= numberofschools; i++) {
        counters[schoolToIndex(students[i  ].getSchool())] += 
        counters[schoolToIndex(students[i-1].getSchool())];
    }

在任何一种情况下,都不会使用最后一个计数/索引,因为这是数据末尾的索引,并且数组将用作起始索引数组。

排序将从第一个元素开始稳定,到最后一个元素结束。我看到了另一种答案,即从最后一个元素开始向后遍历到第一个元素的替代方法,该方法也很稳定,但不像从第一个元素开始那样缓存友好。