33,024
社区成员




template <typename T>
void ShellSort(T arr[], int n) //希尔排序就是增量逐步缩小的直接插入排序
{ //这里采用黄金分割的比例逐次减小增量
int gap = n * 0.382 + 0.5; //所以代码和直接插入排序非常像。区别就是把增量1换成gap
int i, j;
T temp;
while (gap > 0)
{
for (i = gap; i < n; i++)
{
temp = arr[i];
for (j = i - gap; j >= 0; j -= gap)
{
if (temp < arr[j])
arr[j + gap] = arr[j];
else
break;
}
arr[j + gap] = temp;
}
gap = gap * 0.382 + 0.5;
}
}
template <typename T>
void HeapSort(T arr[], int n)
{
for (int i = n / 2 - 1; i >= 0; i--) //建立最大堆,从最后一个非叶节点开始
MaxHeapify(arr, n, i); //对于N规模的堆(0,n-1), n/2-1是最后一个非叶节点
T temp;
for (int i = n - 1; i > 0; i--)
{
temp = arr[i]; //每次取堆顶数据和堆底部数据交换
arr[i] = arr[0]; //并逐步缩小堆的大小
arr[0] = temp;
MaxHeapify(arr, i, 0); //重新筛选堆
}
}
template <typename T>
void MaxHeapify(T arr[], int n, int i)
{
T temp, max_data;
int pos = i;
int left = pos * 2 + 1;
int right = left + 1;
int max_pos;
temp = arr[pos];
while (left < n) //至少有左子树
{
//取左右子树的最大值
max_data = arr[left];
max_pos = left;
if (right < n) //左右子树均有
if (arr[right] > arr[left])
{
max_data = arr[right];
max_pos = right;
}
if (temp < max_data) //节点比左右子树最大值小,继续向下调整
{
arr[pos] = max_data;
pos = max_pos;
left = pos * 2 + 1;
right = left + 1;
}
else
break;
}
arr[pos] = temp; //回填
}
我觉得我写的堆排序中规中矩,没啥大问题啊。难道堆排序还有更强悍的实现方法?template <typename T>
void QuickSort(T arr[], int n) //快速排序
{
QSpartition(arr, 0, n - 1);
InsertSort(arr, n); //最后用插入排序对整个数组排序
}
template <typename T>
void QSpartition(T arr[], int low, int high) //快速排序递归函数
{
// if (low >= high) //有插入排序,不需要这句
// continue;
const int min_insert = 128;
if (high - low < min_insert) //数据小于一定数量的时候用直接插入排序
{
return; //最后用插入排序对整个数组排序
}
int i, j;
T temp;
//下面一段是前中后3个数据进行插入排序
i = (low + high) / 2;
if (arr[i] < arr[low])
{
temp = arr[i];
arr[i] = arr[low];
arr[low] = temp;
}
if (arr[high] < arr[i])
{
temp = arr[high];
arr[high] = arr[i];
arr[i] = temp;
if (arr[i] < arr[low])
{
temp = arr[i];
arr[i] = arr[low];
arr[low] = temp;
}
}
// if (high - low < 3) //小区间用插入排序,这里就不需要判断了
// return; //不用插入排序,只有2个数据的时候排序错误
temp = arr[i];
arr[i] = arr[low + 1]; //中值放在最左边
i = low + 1; //左右边界缩小1
j = high - 1; //边界2个数字插入排序排过,满足左<=中<=右
while (i < j)
{
while (temp < arr[j] && i < j) //从右往左扫描小于目标的值,应该放在左半部分
j--;
if (i < j) //找到后放在左边
arr[i++] = arr[j];
else
break;
while (temp > arr[i] && i < j) //从左往右扫描大于目标的值,要放在右边
i++;
if (i< j)
arr[j--] = arr[i];
else
break;
}
arr[i] = temp; // i = j,正好是分界线,回填目标值
if ((i - low) > 1)
QSpartition(arr, low, i - 1); //递归左边
if ((high - i) > 1)
QSpartition(arr, i + 1, high); //递归右边
}
template <typename T>
void InsertSort(T arr[], int n) //直接插入排序
{
int i, j;
T temp;
for (i = 1; i < n; i++)
{
temp = arr[i];
for (j = i - 1; j >= 0; j--)
{
if (temp < arr[j]) //逐个往前比较,碰到大于目标的,拉过来
arr[j + 1] = arr[j];
else
break;
}
arr[j + 1] = temp; //把目标值填入空位
}
}
[/quote]
多谢了,看你代码里主要有两个优化,我看的书是《大话数据结构》,那个比较低位、高位、中间位的优化叫选取枢轴,添上后代码确实不会栈溢出了,
加入插入排序的优化后,时间会比没有加之前缩短一倍。template <typename T>
void QuickSort(T arr[], int n) //快速排序
{
QSpartition(arr, 0, n - 1);
InsertSort(arr, n); //最后用插入排序对整个数组排序
}
template <typename T>
void QSpartition(T arr[], int low, int high) //快速排序递归函数
{
// if (low >= high) //有插入排序,不需要这句
// continue;
const int min_insert = 128;
if (high - low < min_insert) //数据小于一定数量的时候用直接插入排序
{
return; //最后用插入排序对整个数组排序
}
int i, j;
T temp;
//下面一段是前中后3个数据进行插入排序
i = (low + high) / 2;
if (arr[i] < arr[low])
{
temp = arr[i];
arr[i] = arr[low];
arr[low] = temp;
}
if (arr[high] < arr[i])
{
temp = arr[high];
arr[high] = arr[i];
arr[i] = temp;
if (arr[i] < arr[low])
{
temp = arr[i];
arr[i] = arr[low];
arr[low] = temp;
}
}
// if (high - low < 3) //小区间用插入排序,这里就不需要判断了
// return; //不用插入排序,只有2个数据的时候排序错误
temp = arr[i];
arr[i] = arr[low + 1]; //中值放在最左边
i = low + 1; //左右边界缩小1
j = high - 1; //边界2个数字插入排序排过,满足左<=中<=右
while (i < j)
{
while (temp < arr[j] && i < j) //从右往左扫描小于目标的值,应该放在左半部分
j--;
if (i < j) //找到后放在左边
arr[i++] = arr[j];
else
break;
while (temp > arr[i] && i < j) //从左往右扫描大于目标的值,要放在右边
i++;
if (i< j)
arr[j--] = arr[i];
else
break;
}
arr[i] = temp; // i = j,正好是分界线,回填目标值
if ((i - low) > 1)
QSpartition(arr, low, i - 1); //递归左边
if ((high - i) > 1)
QSpartition(arr, i + 1, high); //递归右边
}
template <typename T>
void InsertSort(T arr[], int n) //直接插入排序
{
int i, j;
T temp;
for (i = 1; i < n; i++)
{
temp = arr[i];
for (j = i - 1; j >= 0; j--)
{
if (temp < arr[j]) //逐个往前比较,碰到大于目标的,拉过来
arr[j + 1] = arr[j];
else
break;
}
arr[j + 1] = temp; //把目标值填入空位
}
}
int FindPos(double *p,int low,int high)
{
double val = p[low];
while (low<high)
{
while(low<high&&p[high]>=val)
high--;
p[low]=p[high];
while(low<high&&p[low]<val)
low++;
p[high]=p[low];
}
p[low]=val;
return low;
}
void QuickSort(double *a,int low,int high)
{
if (!a||high<low)
return;
if (low<high)
{
int pos=FindPos(a,low,high);
QuickSort(a,low,pos-1);
QuickSort(a,pos+1,high);
}
}