具有两个循环c ++的分区算法

时间:2015-11-30 15:46:41

标签: c++ algorithm sorting

我获得了分区算法的伪代码,但我不确定如何实现它。

下面是伪代码和我的实现。如果这是正确的,请告诉我/解释它在做什么。现在我对它有部分了解,但这是不正确的。

输入:0.963,0.003,0.0251,0.353,0.667,0.838,0.335,0.915,0.779,0.833,0.345,0.871,0.089,0.888,0.701,0.735

预期:0.003 0.0251 0.089 0.335 0.345 0.353 0.667 0.701 0.735 0.796 0.833 0.838 0.871 0.888 0.915 0.963

实际:0.003000 0.025100 0.353000 0.667000 0.838000 0.335000 0.915000 0.796000 0.833000 0.345000 0.871000 0.089000 0.888000 0.7 01000 0.735000 0.963000  enter image description here

int partition_data( float xdata[], int ndata, float xmiddle ) {
  int left;
  int right;
  int j,i;
  float temp;

  for(i = 0; i < xmiddle; i ++){
    if(left == right){
      left += 1;
    }
    else{
      for( j = ndata - 1; j >= xmiddle; j--){
        if(left == right){
          right -= 1;
        }
        else{
          temp = xdata[j];
          xdata[j] = xdata[i];
          xdata[i] = temp;

          right -= 1;
          if(left == right){
            left += 1;
            break;
          }
        }
      }
    }
  }

}

3 个答案:

答案 0 :(得分:0)

正如其他人已经说过的那样,无论是在这里还是在Code Review中,伪代码都是非标准的,而且难以阅读(虽然它不是真的,但却是错误的缩进)。

但是,如果您对改进它并不感兴趣,只是想按原样实现它,那么它就是逐字翻译成C语言:

int Partition(float X[], int ndata, float xmiddle)
{
    int left  = 0;
    int right = ndata - 1;
    while(1) {              // 'left' loop
        if(X[left] < xmiddle)
        {
            if(left == right)
                return left + 1;
            left ++;
        }
        else
            while(1) {     // 'right' loop
                if(X[right] >= xmiddle)
                {
                    if(left == right)
                        return left;
                    right --;
                }
                else
                {
                    float tmp = X[left];    // these three lines
                    X[left] = X[right];     // swap the two values
                    X[right] = tmp;         // X[left] and X[right]

                    right --;
                    if(left == right)
                        return left + 1;
                    left ++;
                    break;           // exit the 'right' loop
                }
            }     // end of 'right' loop
    }   // end of 'left' loop
} // end of Parition

代码实际上是C,在C ++中你可以使它成为一个带有类型参数而不是显式float的函数模板,这样函数就可以对不同类型的数组进行分区(只要运算符< }和>=已定义)。您还可以使用std::swap来有效地交换数据并删除显式的tmp变量。

答案 1 :(得分:0)

也许这项任务是实施一个完整的快速排序?

Quicksort采用传统的预增量/预减量Hoare分区方案:

int Partition(float x[], int lo, int hi)
{
float xmiddle = x[(lo+hi)/2];
int left = lo - 1;
int right = hi + 1;
float tmp;
    while (1){
        while (x[++left]  < xmiddle);
        while (x[--right] > xmiddle);
        if(left >= right)
            break;
        tmp = x[left];
        x[left] = x[right];
        x[right] = tmp;
    }
    return right;
}

void QuickSort(float x[], int lo, int hi){
int pivot;
    if (lo < hi){
        pivot = Partition(x, lo, hi);
        QuickSort(x, lo, pivot);
        QuickSort(x, pivot+1, hi);
    }
}

快速排序的一个问题是分区方案中的一个小错误可能适用于大多数数据模式,并且只对特定数据模式失败,因此很难确定快速排序是否真的没有错误。

使用上面的伪代码中的修改版本进行Quicksort。这适用于示例数据,但我不确定它是无bug的。分区应该返回一个指向值== xmiddle:

的索引
int Partition(float X[], int lo, int hi)
{
    int left  = lo;
    int right = hi;
    float xmiddle = X[(lo+hi)/2];
    float tmp;
    while(1) {
        while(X[left] < xmiddle){
            if(left == right)
                return left+1;
            left++;
        }
        while(X[right] >= xmiddle){
            if(left == right)
                return left;
            right--;
        }
        tmp      = X[left];
        X[left]  = X[right];
        X[right] = tmp;
        right --;
        if(left == right)
            return left + 1;
        left ++;
    }
}

void QuickSort(float x[], int lo, int hi){
int pivot;
    if (lo < hi){
        pivot = Partition(x, lo, hi);
        QuickSort(x, lo, pivot);
        QuickSort(x, pivot+1, hi);
    }
}

答案 2 :(得分:0)

算法说明

例程重新排列数据,以便小于提供的xmiddle值的项目保留在数组的左侧(较小的索引处),大于xmiddle的项目放在右侧部分(在更大的指数)。返回值是左侧部分的长度。

变量leftright从两端扫描数组,以查找应交换的项目。

&#39;左循环&#39; (从第4行开始)递增left索引,直到找到大于或等于xmiddle的项(第5行)或直到它到达right位置(第6行)。由于right最初是数组的最后一个索引(后来只能递减),循环最终必须停止递增left

如果left索引符合right,则left下面和xmiddle的所有项都小于left+1,因此xmiddle的长度会返回ndata离开子阵。请注意,如果选择的left大于数组的所有项,则返回值等于数组的长度(xmiddle)。

如果left loop停止在大于或等于right的项目上,那么&#39;否则&#39;第9行的分支执行,右边循环&#39;开始。与xmiddle类似,它会递减right,在left索引符合xmiddle之前逐步执行大于或等于left的所有项。如果两个指数相遇(第11行),则它们下面的所有项目都小于,并且上面和下面的所有项目都大于或等于right;然后返回xmiddle作为左侧部分的长度。

另一方面,如果left索引找到的项目小于xmiddle(即不满足第10行的条件),则需要将其与索引{{ 1}},大于或等于right(它不满足第5行的条件)。然后&#39;否则&#39;第13行的分支被执行。

分支交换两个值(第14行),因此左右两部分变成一个项目更长。为了反映这一点,left索引递减(第15行),然后与left+1进行比较。如果它们相等(第16行),即我们交换相邻的项目,则完成分区,因此left作为左侧部分的长度返回。否则left会增加(第17行),我们会退出&#39;右循环&#39; (第18行)并前往左边环的关闭支架。第20行,将执行带回第4行。

然后left再次增加(即左侧部分增长),直到它遇到正确的部分或找到要交换的项目。等等...

循环不变量是:

  • rightX[i] < xmiddle
  • {li> 0 ≤ i < left X[i] ≥ xmiddle {li> right < i < ndata right - left

并且在循环的每次迭代中,数组的未测试部分减少(差异Platform.runLater(new Runnable() { @Override public void run() { String notebookTitle = notebook.getTitle(); System.out.println("+++: " + notebookTitle); notebooksContainer.getItems().add(notebookTitle); } }); 递减)至少为1。