代码之家  ›  专栏  ›  技术社区  ›  Andreas Grech

修改此快速排序以始终使用最后一个元素作为轴

  •  4
  • Andreas Grech  · 技术社区  · 15 年前

    我有以下几点 Quicksort

    void qqsort(int array[], int start, int end) {
        int i = start; // index of left-to-right scan
        int k = end; // index of right-to-left scan
    
        if (end - start >= 1) { // check that there are at least two elements to sort 
            int pivot = array[start]; // set the pivot as the first element in the partition
            while (k > i) { // while the scan indices from left and right have not met, 
                while (array[i] <= pivot && i <= end && k > i)  // from the left, look for the first element greater than the pivot
                    i++;
                while (array[k] > pivot && k >= start && k >= i) // from the right, look for the first element not greater than the pivot
                    k--;
                if (k > i) // if the left seekindex is still smaller than the right index, swap the corresponding elements
                    swap(array, i, k);              
            }
            swap(array, start, k); // after the indices have crossed, swap the last element in the left partition with the pivot 
            qqsort(array, start, k - 1); // quicksort the left partition
            qqsort(array, k + 1, end); // quicksort the right partition
        } else { // if there is only one element in the partition, do not do any sorting 
            return;
        }
    }
    

    如您所见,该算法始终以第一个元素为轴心: int pivot = array[start];

    我想修改这个算法,使其始终使用子序列的最后一个元素而不是第一个元素,因为我想分析两个实现的物理运行时间。

    我试着换线 int pivot = array[end]; 但该算法随后输出一个未排序的序列:

    //Changes: int pivot = array[end]; 
    unsorted: {5 4 3 2 1}
    *sorted*: {1 2 5 4 3}
    

    //Changes: int pivot = array[(start + end) / 2]; 
    unsorted: {5 3 4 2 1}
    *sorted*: {3 2 4 1 5}
    

    请有人帮助我正确理解这个算法,并告诉我需要做哪些更改才能成功地使这个实现始终选择子序列的最后一个元素作为轴心?

    6 回复  |  直到 5 年前
        1
  •  7
  •   Justin Peel    15 年前

    问题的原因

    问题是你使用 int k = end; . 使用它很好 int i = start; 当您将pivot元素作为数组中的第一个元素时,因为循环中的检查将跳过它( array[i] <= pivot

    解决方案

    要解决此问题,您需要设置 int k = end - 1; 使用最右边的元素作为轴时。您还需要更改将轴交换到左侧和右侧分区之间边界的行:

    swap(array, i, end);
    qqsort(array, start, i - 1);
    qqsort(array, i + 1, end);
    

    k >= i k > i

    应该这样做。

    旁注:

    this presentation 塞吉威克和宾利。

        2
  •  2
  •   Nick Dandoulakis    15 年前

    我没有测试它,但还是要检查它:

    // after the indices have crossed,
    // swap the last element in the left partition with the pivot
    swap(array, start, k);
    

    swap(array, end, i);
    

    或者类似的东西,如果我们选择的话 end 作为支点。

    编辑: 标准

    那么 支点 在分区的逻辑中是固定的。

    最后的 元素,以保持顺序。

    ...
    if (end - start >= 1) {
        // Swap the 1st element (Head) with the pivot
        swap(array, start, pivot_index);
        int pivot = array[start];
    ...
    
        3
  •  1
  •   Svante    15 年前

    第二个提示:如果更改pivot值,还需要更改pivot索引。这不是显式命名,而是 array[start] 在一个点上交换到已排序子序列的“中间”。您需要相应地修改此行。如果索引不在子序列的边缘,则需要在迭代之前首先将其交换到边缘。

    第三个提示:您提供的代码注释过多。您应该能够真正理解这个实现。

        4
  •  0
  •   wqw    15 年前

    单打

    swap(array, start, end)
    

    在初始化pivot之前

    int pivot = array[start]
    
        5
  •  0
  •   Sumit Kumar Saha    12 年前
    #include <time.h>
    #include <stdlib.h>
    #include<iostream>
    #include<fstream>
    using namespace std;
    
    int counter=0;
    void disp(int *a,int n)
    {
    for(int i=0;i<n;i++)
    cout<<a[i]<<" ";
    cout<<endl;
    }
    
    void swap(int a[],int p,int q)
    {
    
    int temp;
    temp=a[p];
    a[p]=a[q];
    a[q]=temp;
    
    }
    
    int partition(int a[], int p, int start, int end)
    {
    swap(a,p,start);// to swap the pivot with the first element of the partition
    counter+=end-start;  // instead of (end-start+1)
    int i=start+1;
    for(int j=start+1 ; j<=end ; j++)
    {
        if(a[j]<a[start])
        {
            swap(a,j,i);
            i++;
    
        }
    
    
    }
    swap(a,start,i-1);  // not swap(a,p,i-1) because p and start were already swaped.....    this was the earlier mistake comitted
    return i-1; // returning the adress of pivot
    }
    
    void quicksort(int a[],int start,int end)
    {
    if(start>=end)
        return;
    
    
    int p=end; // here we are choosing last element of the sub array as pivot
    // here p is the index of the array where pivot is chosen randomly
    
    int index=partition(a,p,start,end);
    
    quicksort(a,start,index-1);
    quicksort(a,index+1,end);
    
    }
    
    int main()
    {
    
    ifstream fin("data.txt");
    int count=0;
    
    int array[100000];
    
    while(fin>>array[count])
    {
        count++;
    }
    quicksort(array,0,count-1);
    /*
    int a[]={32,56,34,45,23,54,78};
    int n=sizeof(a)/sizeof(int);
    disp(a,n);
    
    quicksort(a,0,n-1);
    disp(a,n);*/
    cout<<endl<<counter;
    return 0;
    
    }
    
        6
  •  0
  •   lethal    10 年前

    如果您开始监视从数组的第一个元素到最后一个-1的每个元素,并将最后一个元素作为每次递归的轴心,那么您将得到精确的答案 O(非登录) 时间

    #include<stdio.h>
    void quicksort(int [], int, int);
    int main()
    {
    int n, i = 0, a[20];
    scanf("%d", &n);
    while(i < n)
    scanf("%d", &a[i++]);
    
    quicksort(a, 0, n - 1);
    i = 0;
    while(i < n)
    printf("%d", a[i++]);
    
    }
    void quicksort(int a[], int p, int r)
    {
    int i, j, x, temp;
    if(p < r)
    {
        i = p;
        x = a[r];
        for(j = p; j < r; j++)
        {
            if(a[j] <= x)
            {
                if(a[j] <a[i])
                {
                    temp = a[j];
                    a[j] = a[i];
                    a[i] = temp;
                }
                i++;
            }
    
            else
            {
                temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
        if(x != i)
        {
            temp = a[r];
            a[r] = a[i];
            a[i] = temp;
        }
    
        quicksort(a, p, i - 1);
        quicksort(a, i + 1, r);
    }
    }