基础排序
数据结构与算法之基础排序(冒泡/插入/选择)<十>
希尔排序
希尔排序又称为缩小增量排序。该算法是一个泛化的插入排序,插入排序在序列几乎有序的情况下非常有效。希尔排序利用此特性,分多路并使用不同的间距进行插入排序,当间距为1是则就是简单的插入排序,本质上希尔排序是插入排序的简单拓展
优点
对中等大小的序列非常有效
是所有已知O(n^2)排序算法中最快的
相对简单的排序算法
缺点
较大序列不是个好的选择
不及 归并 堆 快速排序有效
明显比 归并 堆 快速 排序慢
算法
选择合适的间距 将序列分成n路
每路使用插入排序
重复上述过程直至间距为1
堆排序
堆排序是一种基于比较的排序算法,该算法同时属于选择排序。虽然在大多数计算机上的运行效率低于快速排序。但是堆排序最大的优势是在最坏情况下O(nlogn)
关于堆的基础知识参考数据结构与算法之优先队列<九>
以下算法实现仅供参考若有错误欢迎指正
希尔排序
public void sortByShell2(int[] a) {
int d = SIZE;
while (true) {
// 将数组分成d路然后每列进行插入排序
d = d / 2;
// 遍历所有路 每路进行插入排序
for (int j = d; j < arr.length; j++) {
// 若第i个元素大于i-1元素,该位置元素位置正确。小于的话,后移空出位置
if (a[j] < a[j - d]) {
//下个元素位置
int n = j - d;
// 复制为哨兵,即存储待排序元素
int x = a[j];
// 先后移 空出位置
a[j] = a[j - d];
// 循环查找插入位置 直至找到或者到头
while (n >= d && x < a[n - d]) {
a[n] = a[n - d];
//下个元素位置
n = n - d;
}
// 插入到正确位置
a[n] = x;
}
}
// 步长为1时便是插入排序了 排序也就完成了
if (d == 1) {
break;
}
}
}
堆排序
// 调整堆父节点小
public void adjustHeap(int[] heap, int node, int length) {
// 保存被调整的节点
int temp = heap[node];
// 利用完全二叉树的特殊性,父节点与子节点的关系child=father*2+1
int child = node * 2 + 1;
while (child < length) {
// 如果存在右孩子且右孩子小于左孩子
if ((child + 1) < length && heap[child] < heap[child + 1]) {
// 选择小的孩子
++child;
}
// 如果父节点大于孩子中最小的
if (heap[node] < heap[child]) {
heap[node] = heap[child];
// 向下继续调整
node = child;
child = node * 2 + 1;
} else {
break;
}
// 调整完毕 找到了正确位置
heap[node] = temp;
}
}
// 建立堆
public void buildHeap(int[] arr, int length) {
// 根据child=node*2+1可以算出数列中最后一个节点
for (int node = (length - 1) / 2; node >= 0; --node) {
// 从下自上将所有的节点调整一遍
adjustHeap(arr, node, length);
}
}
// 将创建好的堆进行堆排序
public void sortByHeap(int[] array, int length) {
buildHeap(array, length);
int temp;
// 将数组遍历从尾部到顶依次与根节点互换
for (int i = length - 1; i > 0; --i) {
temp = array[i];
array[i] = array[0];
array[0] = temp;
// 将根节点替换后从上向下调整
adjustHeap(array, 0, i);
}
}
到此希尔排序和堆排序介绍完毕