1.插入排序
插入排序较为简单,时间复杂度为O(n^2)
对于数组的插入排序,只需要在待插入元素处向前遍历,通过比较判断是否可以插入即可
对于实现链表的插入排序,不妨设置一个前驱节点(即在head节点前设置一个节点),方便在头结点之前进行统一
的插入操作,在每次插入一个元素时,从前驱节点开始向前遍历,待插入节点与遍历的下一个节点判断是否需要插入
//插入排序
public void insertSort(int [] arr) {
int tmp = 0;
for(int i = 0;i<arr.length-1;i++) {
//从插入元素处向前遍历
for(int j = i+1;j>0;j--) {
//交换
if(arr[j] < arr[j-1]) {
tmp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = tmp;
} else break;//跳出循环
}
}
}
}
//链表实现插入排序
public ListNode insertSortList(ListNode head) {
ListNode p1 = head;
ListNode res = new ListNode(0);
ListNode p2 = res;//设置前驱节点
p2.next = head;
while (p1 != null && p1.next != null){
ListNode insert = p1.next;//插入的节点
boolean isInsert = false;//判断是否有插入
while (p2.next != insert){
//插入节点
if (insert.val <= p2.next.val){//保证插入节点在p2后面
p1.next = insert.next;
insert.next = p2.next;
p2.next = insert;
p2 = res;//p2重置
isInsert = true;
break;
}
p2 = p2.next;
}
p2 = res;//p2重置
if (isInsert == false)//没有插入 节点p1 向前遍历
p1 = p1.next;
}
return res.next;
}
2.希尔排序
希尔排序是在插入排序基础上进行改进的一种排序方法,又叫“缩小增量排序”
设置步长序列k,把间隔为k的元素分为一组,然后分别对其进行插入排序。当最后k为1时,也就是直接插入排序,排序完成
public static void shellSort(int [] arr, int k) {
//k为步长序列
for(;k > 0;k = k/2) {
//插入排序
for (int i = k;i<arr.length;i++) {
for (int j = i;j-k >= 0;j-=k) {
if (arr[j] < arr[j-k]) {
int tmp = arr[j];
arr[j] = arr[j-k];
arr[j-k] = tmp;
} else break;
}
}
}
}
3.归并排序
归并排序采用分治法,时间复杂度为O(N*logN)
关键是合并两个有序数组
public void mergeSort(int [] arr, int bottom, int top) {
if(bottom < top) {
int middle = (bottom + top)/2;
//将arr数组左右分开进行排序
mergeSort(arr,bottom,middle);
mergeSort(arr,middle+1,top);
//合并左右有序数组
merge(arr,bottom,middle,top);
} else return;
}
//合并两个有序数组
public static void merge(int [] arr,int bottom,int middle,int top) {
int [] tmp = new int [top-bottom+1];//临时数组,用以储存合并数组
int i = bottom;
int j = middle+1;
int k = 0;//tmp数组的下标
while(i <= middle && j <= top ) {//两个数组都未遍历完
//小的元素放入tmp中
if(arr[i] <= arr[j]) {
tmp[k++] = arr[i++];
} else {
tmp[k++] = arr[j++];
}
}
while(i <= middle) {
tmp[k++] = arr[i++];
}
while(j <= top) {
tmp[k++] = arr[j++];
}
//将tmp中的元素复制到arr数组中
for(int m = bottom;m <= top;m++)
arr[m] = tmp[m-bottom];
}
4.快速排序
与归并排序一样是采用分治法,时间复杂度为O(N*logN)
关键是每次排序设置一个枢轴元素,小于枢轴元素的元素放在其左边,大的放在右边,那么每次排序完成后枢轴元素都放在数组的正确位置
public void quickSort(int []arr,int bottom,int top) {
if (bottom < top) {
int partion = part(arr,bottom,top);
quickSort(arr,bottom,partion-1);
quickSort(arr, partion+1,top);
}
}
public static int part(int []arr,int bottom,int top) {
int pivot = arr[bottom];//枢轴元素,小的在左,大的在右
while(bottom < top) {
while (arr[top] > pivot && bottom < top)
top--;
arr[bottom] = arr[top];
while (arr[bottom] <= pivot && bottom < top)
bottom++;
arr[top] = arr[bottom];
}
arr[bottom] = pivot;//枢轴元素在数组中排序后的正确位置
return bottom;
}