【问题标题】:Count number of bubble sort swaps in array without doing bubble sort计算数组中冒泡排序交换的次数而不进行冒泡排序
【发布时间】:2016-04-04 20:24:21
【问题描述】:

您好,我正在尝试计算大小为 N 的数组中的冒泡排序交换次数,但我想在不使用冒泡排序的情况下进行,我听说过合并排序,有人已经告诉我它是某种合并排序修改...我不想使用这个基本算法>

void bubbleSort(int * array, int size){
    for(int i = 0; i < size - 1; i++){
        for(int j = 0; j < size - i - 1; j++){
            if(array[j+1] < array[j]){
                int tmp = array[j + 1];
                array[j + 1] = array[j];
                array[j] = tmp;
            }   
        }   
    }   
}  

你们中有人有想法吗?

【问题讨论】:

  • 将要计算交换次数的数组内容复制到另一个数组中,然后对该数组执行冒泡排序。
  • 无论你做什么,我真的建议你不要尝试编写多语言源文件。坚持使用 C 或 C++ 之一。编写多语言源文件是一项艰苦的工作,并且提供的任何优势(如果有的话)都是微乎其微的。
  • 由于你是用 C++ 编程,我建议你使用std::swap。 C语言没有这个特性。
  • @Tomas:为什么你不想执行 bouble 排序?为了不破坏您的数据,还是出于性能原因?
  • C 和 C++ 是不同的语言。选一个!

标签: c++ arrays sorting


【解决方案1】:

看来你可以使用下面的函数来计算掉期的总数:

int calcSwaps(int *array, int size) {
    int cnt = 0;

    for (int i = 0; i + 1 < size; ++i) {
        for (int j = i + 1; j < size; ++j) {
            if (array[j] < array[i]) {
                ++cnt;
            }
        }
    }

    return cnt;
}

主要思想是,在这种类型的排序中,每个元素 array[i] 将与所有元素 array[j]j &gt; iarray[j] &lt; array[i] 交换。

编辑

我会尝试更仔细地解释它以避免误解。解决方案相当简单。考虑冒泡排序算法。让我们看一下初始的未排序数组。如果我们有array[i] 元素,它会被交换多少次?好的,如果array[j] &gt; array[j + 1],我们交换元素array[j]array[j + 1]。根据选择的排序算法,每两个元素最多可以交换一次。此外,如果array[i] &gt; array[j], i &lt; j 它们将被交换,因为我们希望最终得到一个排序数组。很容易看出,在这种情况下,我们只需要获取每个元素array[i],计算array[j], array[j] &lt; array[i], j &gt; i的个数(这将是在排序过程中与array[i]交换的元素个数),最后将每个array[i] 的所有这些数字相加得到答案。

【讨论】:

  • 这不会给出交换次数,而是比较次数。数组是在冒泡排序的第一次迭代更改之后。但在你的情况下它不会改变。
  • @AbhijeetKumarSrivastava 这将给出交换次数。我们不需要更改初始数组即可找到答案。如果你用纸和铅笔手动排序一个小数组,很容易看出。
  • @AbhijeetKumarSrivastava 我编辑了我的答案以使其更具解释性。
【解决方案2】:

修改归并排序,以便除了对其输入进行排序外,还要计算该数组中的反转数。让我们通过归纳来证明它。

基本情况: 简单 - 如果数组大小小于或等于 1,则返回 0 反转

一般情况: 让我们一步一步分析问题。

我们有两个要合并的数组。可能有什么样的反转?反转(i,j)可能在同一半(左或右半),或者 i 可能在左半而 j 可能在右半(我不能在右半,因为我们有约束 i

我们如何计算左右数组的反转次数?在归并排序的归并步骤中,我们得到一个二排序数组(左和右)。对于左数组中的每个元素 left[i],我们想知道右数组中有多少元素 right[j] 严格小于 left[i] .注意,当我们将 left[i] 插入合并数组时,我们知道 j 左侧的每个元素都小于 left[i] (因为它们在 left[i] 之前插入到合并数组中)。因此,每次将 left[i] 插入合并数组时,计数器都会增加 j。

#include <stdio.h>

long long int MS(int a[],int temp[],int left,int right);
long long int Merge(int a[],int temp[],int left,int mid,int right);

long long int MS(int a[],int temp[],int left,int right)
{
    long long int cnt=0;
    int mid;
    if(right>left)
    {
        mid=(right+left)/2;
        cnt=MS(a,temp,left,mid);
        cnt+=MS(a,temp,mid+1,right);
        cnt+=Merge(a,temp,left,mid+1,right);
    }
    return cnt;
}

long long int Merge(int a[],int temp[],int left,int mid,int right)
{
    int i,j,k;
    long long int cnt=0;
    i=left;
    j=mid;
    k=left;
    while(i<=mid-1 && j<=right)
    {
        if(a[i]<=a[j])
            temp[k++] = a[i++];
        else
        {
            temp[k++] = a[j++];
            cnt+=(mid-i);
        }
    }
    while (i<=mid-1)
        temp[k++]=a[i++];
    while(j<=right)
        temp[k++]=a[j++];
    for(i=left;i<=right;i++)
        a[i]=temp[i];
    return cnt;
}

int main()
{
    int *a,*tmp,t,n;
    scanf("%d",&t);
    for(int i=0;i<t;i++)
    {
        scanf("%d",&n);
        a=new int [n];
        tmp=new int [n];
        for(int j=0;j<n;j++)
            scanf("%d",&a[j]);
        printf("%lld\n",MS(a,tmp,0,n-1));
    }
    return 0;
}

【讨论】:

  • 自下而上的合并排序可以用于相同的目的,使用相同的 Merge() 函数。主要区别在于 cnt 将被初始化 = 0,然后在迭代期间(无递归),每次调用 Merge() 的代码将是 cnt += Merge(...)。
【解决方案3】:

注意:It seems to work,但我不确定我的方法是否正确!

让我们有一个示例数组:

{3, 5, 1, 4, 2}

找到最小元素的index。要将其移动到数组的开头,您需要 index 交换。在我的示例中,1 是最小元素,1index 2 是最小元素,因此需要 2 次交换才能将其放置在正确的位置。之后,我们有:

{1, 3, 5, 4, 2}

1 现在位于正确的位置,因此我们可以专注于数组的其余部分以保持简单:

{3, 5, 4, 2}

代码:

#include <algorithm>
#include <vector>

unsigned swaps(std::vector<double>& data) {
    unsigned result = 0;
    while (!data.empty()) {
        auto smallest = std::min_element(data.begin(), data.end());
        result += smallest - data.begin();
        data.erase(smallest);
    }
    return result;
}

See it working (hopefully correctly) online

【讨论】:

  • 为什么要用doubles的向量而不是ints?
  • @Edgar:因为……嗯,我的 C++ 老师使用双精度数组。不过,类型在这里并不重要。
  • 你的老师用double代表int吗?有点奇怪。此外,类型总是很重要,真的。
  • 我们最近在做数值分析,所以我们使用双精度数组,但为了简单起见,在示例输入中经常使用整数。我不明白你的意思是类型总是很重要,它在这里有多重要?
  • 好的,严格来说,为了展示你的算法,你可以使用双打。但是在这种情况下,例如,您可能会花费两倍于我们真正需要存储双精度类型的整数的内存。我敢肯定,C/C++ 的使用意味着编写最佳代码,所以这不是真正的 C/C++ 方式。
【解决方案4】:

您可以遵循三个简单的步骤。制作输入数组的副本,然后每次交换并返回该计数时递增一个计数器。比如:

int bubbleSort(int * array, int size){
    std::vector<int> temp_array(array, array + size);
    int count{0};
    for(int i = 0; i < size - 1; i++){
        for(int j = 0; j < size - i - 1; j++){
            if(temp_array[j+1] < temp_array[j]){
                int tmp = temp_array[j + 1];
                temp_array[j + 1] = temp_array[j];
                temp_array[j] = tmp;
                count++;
            }
        }
    }
    return count;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2016-02-10
    • 1970-01-01
    • 2015-04-10
    • 2013-09-28
    • 1970-01-01
    相关资源
    最近更新 更多