package com.algorithm;
/**
* 插入排序及其变体
*
* List可转化为数组进行排序
* Object数组中的元素必须实现Comparable接口,即元素必须是可比的
*/
public class InsertSort {
/**
* 直接插入排序
*/
public static void insertSort(Object[] a){
Object cur = null; //保存当前遍历到的元素
int len = a.length;
for(int i = 1;i < len;i++){
if(((Comparable)a[i]).compareTo(a[i-1]) < 0){ //如果后一个元素小于前一个
cur = a[i];
a[i] = a[i-1];
int j;
//在前面已经有序的表中查找插入位置,并移动元素
for(j = i-2;j>=0 && ((Comparable)cur).compareTo(a[j]) < 0;j--){
a[j+1] = a[j];
}
a[j+1] = cur;
}
}
}
/**
* 二分插入排序
* 使用二分查找查找插入位置时因为前面元素都已经有序
* 减小查找插入位置的比较次数,但元素移动次数不变
*/
public static void binaryInsertSort(Object[] a){
Object cur = null;
int len = a.length;
for(int i=1;i<len;i++){
if(((Comparable)a[i]).compareTo(a[i-1]) < 0){ //后一个元素小于前一个
cur = a[i];
int low = 0; //下界
int high = i - 1;
while(low <= high){ //找插入位置的索引
int mid = (low + high) / 2;
if(((Comparable)cur).compareTo(a[mid]) < 0){
high = mid - 1;
}else{
low = mid +1;
}
}
for(int j = i -1;j > high;j--){ //把high之后的元素右移
a[j+1] = a[j];
}
a[ high + 1] = cur;
}
}
}
/**
* 2-路插入排序
* 需要一个辅助数组s,及指向s的第一个及最后一个位置的索引,first和last,
* 即从first遍历到final得到的列是有序的
* 2-路插入排序是在二分插入排序的基础上进行改进,
* 减少了排序过程中移动的元素的次数,但增加了辅助空间.
*
*/
public static void twoRoadInsertSort(Object[] a){
int len = a.length;
Object[] s = new Object[len]; //辅助数组
s[0] = a[0];
int first = len;
int last = 0;
for(int i = 1;i < len;i++){
if(((Comparable)a[i]).compareTo(s[0])<0){ //小于s[0],插入到s[0]之前,即从数组最后开始插入
int j;
for(j = first; j < len - 1 && ((Comparable)a[i]).compareTo(s[j])>0;j++){
s[j-1] = s[j];
}
s[j-1] = a[i];
first--;
}else{ //大于s[0],插入到s[0]之后
int j;
//查找插入位置并移动元素
for(j = last; j > 0 && ((Comparable)a[i]).compareTo(s[j])<0;j--){
s[j+1] = s[j];
}
s[j+1] = a[i];
last++;
}
}
System.out.println("first:"+first +" last:"+last);
//重新对a赋值
int count = 0;
for(int i = first;i < len;i++){
a[count++] = s[i];
}
for(int i=0;i<=last;i++){
a[count++] = s[i];
}
}
//test
public static void main(String[] args) {
Integer[] data = {49,38,65,97,76,13,27,49,14};
insertSort(data);
//binaryInsertSort(data);
//twoRoadInsertSort(data);
for(Integer d:data){
System.out.println(d);
}
}
}
希尔排序(改进的插入排序)
package com.sort;
/**
* 希尔排序(它也是一种插入排序)
* 原理:首先根据增量,将相隔增量位置的元素组成一个子序列,
* 对子序列进行插入排序,一趟排序后若干子序列已经有序。
* 然后减少增量,继续重复上述操作,最后一趟排序的增量必为1,
* 即对整个序列进行一次插入排序。最后一趟排序后整个列表有序。
*
* 产生希尔排序的原因:
* 1.若待排记录序列"基本有序",即i记录之前的所有记录中
* 大于i的记录较少,这时候插入排序的效率可以大大提高
* 2.列表元素较少时,插入排序的效率也比较高。
*/
public class ShellSortDemo {
/**
* 根据设置的增量多次排序
*/
public static void shellSort(Object[] a){
//最后一个增量必为1。即对整个序列进行一次插入排序
int[] dks = {5,3,1};
//进行dsk.length插入排序
for(int i=0;i<dks.length;i++){
ShellInsert(a, dks[i]);
}
}
/**
* 某一趟排序,增量为dk。
* 意思为:将相隔dk的记录组成一个子序列。
* 对子序列进行插入排序。
* 比如:增量为5时
* 初始记录 49 38 65 97 76 13 27 49 55 4
* 子序列1: 49 13
* 子序列2: 38 27
* 子序列3: 65 49
* 子序列4: 97 55
* 子序列5: 76 4
* 可对上述自序列分别进行插入排序
*/
private static void ShellInsert(Object[] a,int dk){
int len = a.length;
Object cur = null;
for(int i=dk;i<len;i++){
if(((Comparable)a[i]).compareTo(a[i-dk]) < 0){
cur = a[i];
int j;
//在左边有序表中查找插入位置,查找过程中元素右移
for(j = i -dk; j>=0 && ((Comparable)cur).compareTo(a[j]) < 0;j-=dk){
a[j+dk] = a[j];
}
a[j+dk] = cur; //找到正确插入位置
}
}
}
//just for test
public static void main(String[] args) {
Integer[] data = {49,38,65,97,76,13,27,49,55,4};
shellSort(data);
for(Integer d:data){
System.out.println(d);
}
}
}
分享到:
相关推荐
二分法插入排序是直接插入排序的一种变体,它使用二分搜索来找到合适的插入位置。该算法的时间复杂度为O(n log n),空间复杂度为O(1)。 在上面的代码中,我们可以看到,二分法插入排序的实现是通过一个 Outer Loop ...
- 折半插入排序是插入排序的一个变体,它在插入元素时使用二分查找来确定插入位置,从而减少比较次数。 - 在查找插入位置时,将数组分成已排序部分和未排序部分,用二分查找找到已排序部分中合适的位置,然后将...
4. **希尔排序**:希尔排序是插入排序的一种优化版本,通过比较相距一定间隔的元素,将元素逐步拉近到有序状态,最后再进行一次简单的插入排序,大大提高了效率。 5. **直接插入排序**:直接插入排序是将未排序的...
这里我们将深入探讨六种基本的排序算法:冒泡排序、插入排序、选择排序、希尔排序、堆排序以及归并排序,这些都是快速排序算法的基础。下面,我们将逐一介绍这些算法的工作原理、效率特点及其应用场景。 1. **冒泡...
根据插入方式的不同,插入排序有多种变体,其中直接插入排序是最常见的一种。 **直接插入排序**: 1. **基本操作**:直接插入排序的基本操作是在已排序的序列中为待插入元素找到合适的位置,并将其插入。这个过程...
本资源集成了五种经典的排序算法:冒泡排序、选择排序、鸡尾酒排序(也称作双向冒泡排序)、插入排序以及希尔排序。以下是对这些排序方法的详细说明: 1. **冒泡排序**: 冒泡排序是一种简单的排序算法,通过重复...
主要分为直接插入排序和希尔排序两种变体。 - 直接插入排序:将未排序的元素逐个插入已排序的序列中,保持已排序部分的有序性。它的平均时间复杂度为O(n^2),但对小规模或接近有序的数据,性能较好。 - 希尔排序:...
希尔排序是插入排序的一种更高效的变体,通过将元素按照一定间隔分组,对每组进行插入排序,然后逐渐减小间隔,直到间隔为1,此时整个列表相当于一个组。在`ShellSort`函数中,`d`是初始间隔,每次循环后都会减半,...
这八种算法包括:直接插入排序、希尔排序、冒泡排序、快速排序、基数排序、堆排序以及2路归并排序和折半插入排序。下面我们将对每一种算法进行详细介绍。 1. **直接插入排序**:这是一种简单的排序算法,它将待排序...
主要有直接插入排序和折半插入排序两种变体。 1. 直接插入排序:将待排序的元素逐个插入到已排序的序列中,每次插入都要与已排序的部分进行比较,找到合适的位置。该算法的时间复杂度为O(n^2),是稳定的排序方法。 ...
插入排序有几种变体,包括直接插入排序、折半插入排序、链表插入排序以及希尔排序。 **直接插入排序**是最基础的版本,其基本思想是假设前i-1个元素已经排序,然后将第i个元素与已排序的元素依次比较,找到合适的...
在笔试面试中,尽管插入排序的考察频度不高,但其基本概念和操作容易被设计为选择题或填空题来考察时间复杂度和空间复杂度的理解,因此了解插入排序的原理及其性能特点仍然是必要的。 除了插入排序,本次详解还包括...
总结来说,插入排序及其变体是数据结构中重要的排序算法,它们在不同场景下各有优势,理解并掌握这些算法的原理和实现细节,对于提升编程效率和解决实际问题有着重要作用。在实际应用中,需要根据数据特性、内存限制...
常见的内部排序算法包括直接插入排序、希尔排序、选择排序等。 2. **外部排序**:外部排序通常用于处理大数据集,因为数据量太大无法一次性装入内存。它需要在内存和外部存储之间进行多次交互才能完成排序。外部...
`ShellSorter` 类中的 `Sort` 方法采用了Hibbard增量序列(即`inc`的计算方式),这是一种常见的希尔排序变体,可以加快排序速度。 这四种排序算法在效率上有所不同。冒泡排序和选择排序的时间复杂度通常是O(n^2),...
希尔排序是一种基于插入排序的算法,通过允许相隔某个增量的记录进行比较和交换来改进插入排序的性能。随着排序过程的推进,这个增量会逐渐减小,最终变为1。这时,希尔排序退化为直接插入排序。 **时间复杂度**:...
插入排序是基于一个元素一个元素地插入到已排序序列中的基本排序方法,它包含直接插入排序、折半插入排序和2路插入排序等变体。选择排序的策略是找到序列中的最小(或最大)元素,并将它与序列的起始位置进行交换,...
8. 希尔排序:插入排序的改进版,通过增量序列进行预排序,时间复杂度通常优于O(n^2)。 9. 布隆排序:基于概率的排序,不是稳定的排序,时间复杂度接近O(n)。 在本项目中,开发者对比了这些排序算法在处理20万个...
2-路插入排序是插入排序的一种变体,适用于部分有序的数据。 6. **希尔排序** 希尔排序是插入排序的改进版本,通过增量序列对数组进行分组,然后对每个子序列进行插入排序。 7. **快速排序** 快速排序是一种高效的...
插入排序有直接插入排序和希尔排序两种变体。直接插入排序是简单的排序算法,通过逐步将未排序元素插入已排序序列来完成排序,时间复杂度为O(n^2)。希尔排序是插入排序的一种优化,通过设置增量序列来减少比较次数,...