文章目录
- 1.只申请一次内存,避免多次递归调用时反复的申请和释放内存,提高程序运行效率
- 2.不申请内存,在原数组上直接排序
- 优化比较总结
对链接中快速排序进行代码优化
https://blog.csdn.net/qq_21201267/article/details/80993672#t6
1.只申请一次内存,避免多次递归调用时反复的申请和释放内存,提高程序运行效率
/** 6-1-opti1.快速排序(best version)(三数取中基准+希尔排序+基准群)(opti1,只申请一次内存)* 对数组找出一个中间大小的合适哨兵,把小于哨兵的放左边,大于哨兵的放右边,中间是等于哨兵的* 分别对左右递归调用快排*/void partion1_opti1(int *arr, size_t left, size_t right, size_t &lessPnum, size_t &largePnum, int *temp)//数据分段
{selectmedianofthree1(arr,left,right); //找出中间大小的哨兵,让分段尽量均匀,提高效率int pval = arr[left]; //中间大小的数赋值给哨兵int tempLindex=0, tempRindex = right-left; //临时数组的首末位下标for(int i = left+1; i <= right; ++i){if(pval > arr[i]) //比哨兵小的放在左边,从左边首位往中间写入,记录下比哨兵小的有多少个{temp[tempLindex++] = arr[i];++lessPnum;}if(pval < arr[i]) 比哨兵大的放在右边,从右边末位中间写入,记录下比哨兵大的有多少个{temp[tempRindex--] = arr[i];largePnum++;}}for( ; tempLindex <= tempRindex; ++tempLindex)//中间还未被写入的位置,写入哨兵(哨兵可能是多个相同的值){temp[tempLindex] = pval;}for(int i = left, j=0; i <= right; ++i){arr[i] = temp[j++]; //把分好段的数组写回原数组{[小于哨兵的],[等于哨兵的],[大于哨兵的]}}
}
void qsort1_opti1(int *arr, size_t left, size_t right, int deep, int *temp)
{if(left >= right){return;}else if(right-left == 1)//只有两个数直接比较交换(也可以设置长度小于X(比如10),调用其他排序,如归并,减少不必要的调用快排){if(arr[left]>arr[right]){swap(arr[left], arr[right]);}}else if(right-left > 1 && right-left < 20) //数组长度较小时,调用希尔排序,减少调用快排{size_t len = right - left + 1;shellsort(len, &arr[left]); //数组首地址为&arr[left]}else{size_t lessPnum = 0, largePnum=0;partion1_opti1(arr,left,right,lessPnum,largePnum,temp); //数据分段,{[小于哨兵],[等于哨兵],[大于哨兵]}size_t pl_index = left + lessPnum; //首位哨兵的下标size_t pr_index = right - largePnum; //末位哨兵的下标if(pr_index == right && pl_index != left) //哨兵群位于数组最右边,且左边还有数据{qsort1_opti1(arr,left,pl_index-1,deep,temp); //只对左边非哨兵数据快排}else if(pl_index == left && pr_index != right) //哨兵群位于数组最左边,且右边还有数据{qsort1_opti1(arr,pr_index+1,right,deep,temp); //只对右边非哨兵数据快排}else if(pl_index == left && pr_index == right) //全部是哨兵,两侧无数据,退出{return;}else //两侧都有非哨兵数据,对两侧调用快排{qsort1_opti1(arr,left,pl_index-1,deep,temp);qsort1_opti1(arr,pr_index+1,right,deep,temp);}}
}
void quicksort1_opti1(size_t dsize, int *arr)
{if(dsize <= 1) //预防特殊情况下后面代码失效{return;}size_t left = 0, right = dsize-1;int deep = 0; //可以打印显示出调用的层数int *temp = new int [dsize]; //一次性开辟堆空间存放临时数组qsort1_opti1(arr,left,right,deep,temp);delete [] temp; //释放临时数组temp = NULL; //指针置空
}
运行比较: 优化1效率提升
2.不申请内存,在原数组上直接排序
/** 6-1-opti2.快速排序(best version)(三数取中基准+希尔排序+基准群)(不申请内存)* 对数组找出一个中间大小的合适哨兵,把小于哨兵的放左边,大于哨兵的放右边,中间是等于哨兵的* 分别对左右递归调用快排*/
void partion1_opti2(int *arr, size_t left, size_t right, size_t &pl_index, size_t &pr_index)//数据分段
{selectmedianofthree1(arr,left,right); //找出中间大小的哨兵,让分段尽量均匀,提高效率int pval = arr[left]; //中间大小的数赋值给哨兵size_t i = left, j = right;while(i < j){while(i < j && pval <= arr[j]) //把<=改成<,则哨兵群都在左边,下面相应代码可减少--j;swap(arr[i],arr[j]);while(i < j && pval >= arr[i])// =号至少有一个才行,一个等号,忽略下面半边集合哨兵代码是最高效的++i;swap(arr[i],arr[j]);}size_t pindex = i;size_t leftpnum = 0, rightpnum = 0; //左右跟哨兵相等的元素个数pl_index = pindex;//记得初始化!!!之前没有写,假如进不去for,没有初始化,就越界了pr_index = pindex;if(pindex != 0)//!!!如果pindex = 0,下面 i = pindex - 1 越界{for(i = pindex-1; i >= left; --i)//左边哨兵群向中间集合,哨兵都在右边,即可忽略以下代码{if(arr[i] == pval){++leftpnum;pl_index = pindex - leftpnum;swap(arr[i],arr[pl_index]);}if(i == left) //size_t 做减法要小心越界break;}}for(i = pindex+1; i <= right; ++i)//右边哨兵群向中间集合,哨兵都在左边边,即可忽略以下代码{if(arr[i] == pval){++rightpnum;pr_index = pindex + rightpnum;swap(arr[i],arr[pr_index]);}}
}
void qsort1_opti2(int *arr, size_t left, size_t right, int deep)
{if(left >= right){return;}else if(right-left == 1)//只有两个数直接比较交换(也可以设置长度小于X(比如10),调用其他排序,如归并,减少不必要的调用快排){if(arr[left]>arr[right]){swap(arr[left], arr[right]);}}else if(right-left > 1 && right-left < 20) //数组长度较小时,调用希尔排序,减少调用快排{size_t len = right - left + 1;shellsort(len, &arr[left]); //数组首地址为&arr[left]}else{size_t pl_index; //首位哨兵的下标size_t pr_index; //末位哨兵的下标partion1_opti2(arr,left,right,pl_index,pr_index); //数据分段{[小于哨兵][等于哨兵][大于哨兵]}if(pr_index == right && pl_index != left) //哨兵群位于数组最右边,且左边还有数据{qsort1_opti2(arr,left,pl_index-1,deep); //只对左边非哨兵数据快排}else if(pl_index == left && pr_index != right) //哨兵群位于数组最左边,且右边还有数据{qsort1_opti2(arr,pr_index+1,right,deep); //只对右边非哨兵数据快排}else if(pl_index == left && pr_index == right) //全部是哨兵,两侧无数据,退出{return;}else //两侧都有非哨兵数据,对两侧调用快排{qsort1_opti2(arr,left,pl_index-1,deep);qsort1_opti2(arr,pr_index+1,right,deep);}}
}
void quicksort1_opti2(size_t dsize, int *arr)
{if(dsize <= 1) //预防特殊情况下后面代码失效{return;}size_t left = 0, right = dsize-1;int deep = 0; //可以打印显示出调用的层数qsort1_opti2(arr,left,right,deep);
}
运行效率:
优化比较总结
以下数据为5次运行的平均数据
windows下效率提升:optimization1 -----6%----- optimization2 -----14%-----
linux 下效率提升:optimization1 -----2%----- optimization2 -----20%-----
测试程序运行时间shell脚本
https://blog.csdn.net/qq_21201267/article/details/81840299
最后特别感谢阿福同学的帮忙调试找BUG!!!