数组的插入排序
如果是数组的插入排序,则数组的前面部分是有序序列,每次找到有序序列后面的第一个元素(待插入元素)的插入位置,将有序序列中的插入位置后面的元素都往后移动一位,然后将待插入元素置于插入位置。
/**
* 插入排序:插入排序是一种简单直观的排序算法,插入排序在实现上,
* 通常采用in-place排序(即只需用到O(1)的额外空间的排序),
* 因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。
* 步骤:
* 1> 从第一个元素开始,该元素可以认为已经被排序
* 2> 取出下一个元素,在已经排序的元素序列中从后向前扫描
* 3> 如果该元素(已排序)大于新元素,将该元素移到下一位置
* 4> 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
* 5> 将新元素插入到该位置后
* 6> 重复步骤2~5
*
* 应用: 插入排序不适合对于数据量比较大的排序应用。但是,如果需要排序的数据量很小,
* 比如量级小于千,那么插入排序还是一个不错的选择。 插入排序在工业级库中也有着广泛的应用,
* 在STL的sort算法和stdlib的qsort算法中,都将插入排序作为快速排序的补充,
* 用于少量元素的排序(通常为8个或以下)
* @param array
*/
public void insertionSort(int[] array) {
int l = array.length;
for (int i = 1; i < l; i++){
//先获取一个数据
int get = array[i];
int j = i - 1;
//将获取的数据右向左进行比较
while (j >= 0 && array[j] > get){
// 如果该手牌比抓到的牌大,就将其右移
array[j + 1] = array[j];
j--;
}
array[j + 1] = get; // 直到该手牌比抓到的牌小(或二者相等),将抓到的牌插入到该手牌右边(相等元素的相对次序未变,所以插入排序是稳定的)
}
}
单链表的插入排序
对于链表而言,插入元素时只要更新相邻节点的指针即可,不需要像数组一样将插入位置后面的元素往后移动,因此插入操作的时间复杂度是 O(1),但是找到插入位置需要遍历链表中的节点,时间复杂度是 O(n),因此链表插入排序的总时间复杂度仍然是 O(n^2),其中 n是链表的长度。
对于单向链表而言,只有指向后一个节点的指针,因此需要从链表的头节点开始往后遍历链表中的节点,寻找插入位置。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode insertionSortList(ListNode head) {
if(head==null){
return null;
}
//创建哑节点:便于在head节点之前插入节点
ListNode dummyHead=new ListNode(0);
dummyHead.next=head;
//创建lastSorted为链表已排序部分的最后一个节点并初始化
ListNode lastSorted=head;
//创建curr为待插入的元素并初始化
ListNode curr=head.next;
while(curr!=null){
//如果lastSorted.val<=curr.val,说明curr应该位于lastSorted之后,将lastSorted后移一位,curr变成新的lastSorted
if(lastSorted.val<=curr.val){
lastSorted=lastSorted.next;
}else{
//否则,从链表的头结点开始往后遍历链表中的节点,寻找插入curr的位置。从链表头开始遍历,令pre为插入curr的前一个节点
ListNode pre=dummyHead;
while(pre.next.val<=curr.val){
pre=pre.next;
}
//对curr的插入
lastSorted.next=curr.next;
curr.next=pre.next;
pre.next=curr;
}
//下一个待插入的元素
curr=lastSorted.next;
}
return dummyHead.next;
}
}