插入排序分为
1.直接插入排序,
2.二分插入排序(又称折半插入排序),
3.链表插入排序,
4.希尔排序(又称缩小增量排序)
直接插入
分析:
直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列!
示意图:
希尔排序
分析:
1.希尔排序是希尔(Donald Shell) 于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。
2.基本思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成-一组,算法便终止
示意图:
实现编码:
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
//int[] arr = { 8, 9, 1, 7, 2, 3, 5, 4, 6, 0 };
// 创建要给10个的随机的数组
int[] arr = new int[10];
for (int i = 0; i < 10; i++) {
arr[i] = (int) (Math.random() * 10); // 生成一个[0, 10) 数
}
shellSort(arr); //交换式
shellSort2(arr);//移位方式
System.out.println(Arrays.toString(arr));
}
// 使用逐步推导的方式来编写希尔排序
// 希尔排序时, 对有序序列在插入时采用交换法,
// 思路(算法) ===> 代码
public static void shellSort(int[] arr) {
int temp = 0;
int count = 0;
// 根据前面的逐步分析,使用循环处理
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arr.length; i++) {
// 遍历各组中所有的元素(共gap组,每组有个元素), 步长gap
for (int j = i - gap; j >= 0; j -= gap) {
// 如果当前元素大于加上步长后的那个元素,说明交换
if (arr[j] > arr[j + gap]) {
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
System.out.println("希尔排序第" + (++count) + "轮 =" + Arrays.toString(arr));
}
}
//对交换式的希尔排序进行优化->移位法
public static void shellSort2(int[] arr) {
// 增量gap, 并逐步的缩小增量
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
// 从第gap个元素,逐个对其所在的组进行直接插入排序
for (int i = gap; i < arr.length; i++) {
int j = i;
int temp = arr[j];
if (arr[j] < arr[j - gap]) {
while (j - gap >= 0 && temp < arr[j - gap]) {
//移动
arr[j] = arr[j-gap];
j -= gap;
}
//当退出while后,就给temp找到插入的位置
arr[j] = temp;
}
}
}
}
}
/*控制台展示*/
希尔排序第1轮 =[2, 2, 3, 6, 6, 2, 6, 7, 7, 9]
希尔排序第2轮 =[2, 2, 3, 2, 6, 6, 6, 7, 7, 9]
希尔排序第3轮 =[2, 2, 2, 3, 6, 6, 6, 7, 7, 9]
[2, 2, 2, 3, 6, 6, 6, 7, 7, 9]
二分插入
分析:
1.二分插入排序,改进插入直接插入排序 在新元素插入到已序数组时,用二分法查找插入的位置
2. 最好情况:每次插入的位置k都是已序数组的最后的位置,则无需再执行移位赋值操作 O(n*log2n)
3. 最坏情况:每次插入的位置k都是已序数组的最前的位置,则整个已序数组需要移位赋值 O(n^2)
思路图:
实现代码
public class insertSort111 {
public static void main(String[] args) {
int[] a = new int[10];
//random array
for (int i = 0; i < a.length; i++) {
Random rd = new Random();
a[i] = rd.nextInt(10);
}
System.out.println("随机的数组 :");
System.out.println(Arrays.toString(a));
System.out.println();
System.out.println("二进制插入排序后 :");
//插入排序
// 外循环规定从第二个元素开始,将元素插入到已排好的数组中
for (int i = 1; i < a.length; i++) {
//得到插入的位置
int k = findByBinary(a, i);
//保存a[i]
int key = a[i];
//元素后移
for (int j = i - 1; j >= k; j--) {
a[j + 1] = a[j];
}
a[k] = key;
}
System.out.println(Arrays.toString(a));
}
public static int findByBinary(int[] a, int i) {
int highIndex = i - 1;
int lowIndex = 0;
int mid = -1;
while (lowIndex <= highIndex) {
mid = (highIndex + lowIndex) / 2;
if (a[i] >= a[mid]) {
//若相等,保证新元素插在旧元素后面
lowIndex = mid + 1;
} else {
highIndex = mid - 1;
}
}
return lowIndex;
}
}
链表插入
分析:
通俗来说: 用插入排序对链表排序
举个例子
1.将待插入数3拿出来
2.将比3大的数字往后挪
3 .将待插入数3插入空位
以此类推到最后一个元素
实现代码:
/*
ListNode
*/
public class ListNode {
int val;
ListNode nextNode;
ListNode(int val) {
this.val = val;
this.nextNode = null;
}
}
public class Graph1 {
/*
1.首先判断head是不是空,为空就直接返回null
2.然后从head.next开始循环遍历,删除相等于val的元素
3.最后判断head是否和val相等,若相等,head = head.next
(这里最后判断head是有原因的,因为head只是一个节点,只要判断一次,如果最先判断head就比较麻烦,因为如果等于val,head就要发生变化)
这里也体现出为什么设计链表的时候要空出一个头结点
*/
static ListNode head=null;
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] input=new int[]{1,2,3,3,4,4,5};
ListNode listNode=buildListNode(input);
head=listNode;
while(listNode!=null){
System.out.println("val"+listNode.val+"/listNode"+listNode.nextNode);
listNode=listNode.nextNode;
}
head=removeElements(head,3);
listNode=head;
while(listNode!=null){
System.out.println("val"+listNode.val+"/listNode"+listNode.nextNode);
listNode=listNode.nextNode;
}
}
private static ListNode buildListNode(int[] input){
ListNode first = null,last = null,newNode;
int num;
if(input.length>0){
for(int i=0;i<input.length;i++){
newNode=new ListNode(input[i]);
newNode.nextNode=null;
if(first==null){
first=newNode;
last=newNode;
}
else{
last.nextNode=newNode;
last=newNode;
}
}
}
return first;
}
private static ListNode removeElements(ListNode head,int val){
if(head==null){
return null;
}
ListNode p=head,q=head.nextNode;
while(q!=null){
if(q.val==val){
p.nextNode=q.nextNode;
q=q.nextNode;
}else{
p=p.nextNode;
q=q.nextNode;
}
}
if(head.val==val){
return head.nextNode;
}
return head;
}
}