【问题标题】:Finding the beginning index for counting sort查找计数排序的起始索引
【发布时间】:2015-11-09 21:09:57
【问题描述】:
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的开始索引是学校的学生人数。我不知道该怎么做是让开始索引是之前学校的累计学生数。

例如,如果我想要 UCLA 的开始索引,我需要将 UCB 和 UCD 和 UCI 的学生数相加才能得到这个桶的开始索引。

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

有什么方法可以用来做这个吗?我使用递归吗?

【问题讨论】:

  • 你标记这个bucket-sort有什么原因吗?

标签: c++ sorting bucket-sort counting-sort


【解决方案1】:

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

为此,您使用一种称为部分和的算法。

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

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

(您可以手动操作或使用&lt;numeric&gt; 中的std::partial_sum() 函数。)

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

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

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

希望这会有所帮助。

【讨论】:

    【解决方案2】:

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

    使用两个临时变量 sum 和 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())];
        }
    

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-17
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多