其他分享
首页 > 其他分享> > 希尔排序和快速排序的比较

希尔排序和快速排序的比较

作者:互联网

为什么要写这个?

快速排序

  1. 选取一个pivot,挖出来,腾出来一个A坑(挖坑)
  2. person1负责:从右往左找第一个比pivot小的元素挖出来填A坑(小的往左放),挖出来的这个元素腾出来一个B坑(需要有一个比pivot大的元素来填)
  3. person2负责:从左往右找第一个比pivot大的元素填B坑(大的往右放),挖出来的这个元素腾出来一个C坑(需要有一个比pivot小的元素来填)
  4. 不断重复2和3步骤,直到person1和person2相遇,此时将pivot放入person1所在的坑中。(确定了pivot最终的位置)
  5. 对pivot左边的子数组和pivot右边的子数组进行1到4步骤的循环。

快速排序的代码


int partition(vector<int>& arr, long long left, long long right) {
    // 1. 挖坑
    int tmpPivot = arr[left]; // 在最左边挖了一个坑,并临时保存了坑中的元素,此时left指向这个坑

    // 2. 交替填坑
    while (left < right) {
        while (left < right && arr[right] >= tmpPivot) right--;// 从右往左找第一个小于pivot的元素
        arr[left] = arr[right]; //用这个元素填当前坑(left所在位置),那么right指向新腾出来的一个坑,此时我们让right停止
        while (left < right && arr[left] <= tmpPivot) left++; // 从左往右找第一个大于pivot的元素
        arr[right] = arr[left]; // 用这个元素填当前坑(right所在位置)
    }
    // 当left和right相遇(此时还有一个坑,那么用pivot填充)

    // 3. 用枢轴来埋最后一个坑(确定最终位置)
    arr[left] = tmpPivot;
    return left;
}

void quickSort(vector<int>& arr, long long left, long long right) {
    // 由于left和right由上一步的pivot计算得来,上一步的pivot可能是0,1,arr.size()-1,arr.size() - 2这四种情况
    // 他们分别会导致left == right + 1, left == right, left == right + 1, left == right这几种边缘情况,是不需要继续做快排的
    if (left >= right) {
        return;
    }
    long long pivot = partition(arr, left, right); // 做局部排序并返回枢轴的index
    quickSort(arr, left, pivot - 1);
    quickSort(arr, pivot + 1, right);
}

快速排序时间复杂度分析

希尔排序

  1. 确定一个分组数k,开始的时候是n / 2
  2. 根据分组数,将数组分成{v[0], v[k], v[2k] ...} , {v[1], v[k + 1], v[2k + 1] ...} , ...
  3. 对每个组的组内元素分别进行插入排序
  4. 减少分组数,重复1、2、3步骤,直到分组数为1,做最后一次插入排序。

希尔排序的代码


void shellSort(vector<int> & arr) {
    int size = arr.size();
    if (size == 1 || size == 0) return;
    int groupNum = size; // 分成多少组(等于是同组之间的元素间隔大小)
    int elemNumPerGroup; // 每组中元素个数
    while (groupNum > 2) { // 当分组数变为1的时候,做最后一次插排
        // 计算分组和组内元素个数
        groupNum /= 2;
        elemNumPerGroup = size / groupNum;
        for (int g = 0; g < groupNum; g++) { 
            for (int i = 1; i < elemNumPerGroup; i++) { 
                int now = g + i * groupNum; 
                if (now >= size) { 
                    break;
                }
                int tmp = arr[now];
                int pre = g + (i - 1) * groupNum; 
                while (pre >= 0 && arr[pre] > tmp) {
                    arr[pre + groupNum] = arr[pre]; 
                    pre -= groupNum; 
                }
                arr[pre + groupNum] = tmp; 
            }
        }
    }
}

希尔排序的时间复杂度分析

希尔排序速度碾压快速排序的情况

数组长度为10w的结果

范围\排序算法 快速排序 希尔排序
0~1000000 0.026 s 0.073 s
0~100000 0.026 s 0.074 s
0~10000 0.029 s 0.064 s
0~1000 0.041 s 0.055 s
0~100 0.229 s 0.044 s
0~10 2.04 s 0.033 s
0~5 4.083 s 0.032 s

继续测试

数组长度为1w的结果

范围\排序算法 快速排序 希尔排序
0~1000000 0.002 s 0.005 s
0~100000 0.002 s 0.004 s
0~10000 0.002 s 0.004 s
0~1000 0.002 s 0.004 s
0~100 0.003 s 0.003 s
0~10 0.021 s 0.002 s
0~5 0.047 s 0.002 s

结论

标签:arr,right,用时,希尔,排序,快速,left
来源: https://www.cnblogs.com/LeisureLak/p/16575619.html