本书我先看了排序这一章节,因为在牛客网做题的时候,题目总是会涉及到排序问题,所以要复习排序问题。
1、插入排序
插入排序是从后向前扫描,找到相应位置并插入,比如数组34,8,64,52,32,21.对其进行排序
第一趟:8,34,64,52,32,21.因为8<34,就插在34前面
第二趟:8,34,64,52,32,21.因为34<64,顺序不变
第三趟:8,34,52,64,32,21.因为52<64,所以改变顺序,接着52又继续和34相比较,比34大,也比8大,所以就在它们前面
第四趟:8,32,34,52,62,21.
第五趟:8,21,32,34,52,62.
排序结束,接下来就是算法实现
private static void Insert(int[] arr) {
for(int i=0;i<arr.length;i++) {
int temp=arr[i];
for(int j=i;j>0 && temp<arr[j-1];j--) {
arr[j]=arr[j-1];
arr[j-1]=temp;
}
}
for (int i : arr) {
System.out.println(i);
}
}
2、希尔排序
先将整个待排序的序列分几次进行分割成若干份子序列,后按照份数进行进行直接插入排序,直到相邻的数进行比较。
举个栗子^-^:81,94,11,96,12,35,17,95,28,58,41,75,15进行排序
先分成5份排序后:35,17,11,28,12,41,75,15,96,58,81,94,95
接着分成3份排序后:28,12,11,35,15,41,58,17,94,75,81,96,95
最后分成1份排序后:11,12,15,17,28,35,41,58,75,81,94,95,96
import java.util.Scanner;
/**
* 希尔排序
*
* @author thinkpad_ljj
*
*/
public class Shellsort {
public static void main(String[] args) {
Scanner read = new Scanner(System.in);
int n = read.nextInt();
int[] arr = new int[n];
for(int i = 0;i<n;i++) {
arr[i]=read.nextInt();
}
shellSort(arr);
}
/**
* 从小到大排序
* 确定每次分成gap份子序列,gap每次缩短为原来的一半
* 当确定了步长后,就要按照i的顺序找到步长所对应的值
* 和间隔步长的数值进行比较,若小于就交换
* @param arr 传入数组序列
*/
private static void shellSort(int[] arr) {
//先确定分成多少分子序列
for(int gap = arr.length/2;gap>0;gap/=2) {
for(int i=gap;i<arr.length;i++) {
int temp = arr[i];
for(int j=i;j>=gap&&arr[j-gap]>temp;j-=gap) {
arr[j]=arr[j-gap];
arr[j-gap]=temp;
}
}
}
}
}
3、堆排序
基本思想:这里讨论的是大根堆,小根堆同理,先对堆进行大根堆处理即每个的父节点都是较大的,然后开始排序,根节点和最后的叶子结点进行交换,接着又进行大根堆处理,如此循环直到排序结束。
package sort;
import java.util.Scanner;
/**
* 堆排序
*
* @author thinkpad_ljj
*
*/
public class HeapSort {
public static void main(String[] args) {
Scanner read = new Scanner(System.in);
int n = read.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = read.nextInt();
}
heapSort(arr);
}
/**
* 堆排序
*
* @param arr数组序列
*/
private static void heapSort(int[] arr) {
/* 构建大顶堆 */
for (int i = arr.length / 2 - 1; i >= 0; i--) {
buildHeap(arr, i, arr.length);
}
/* 调整堆结构+交换堆顶元素和末尾元素 */
// for(int j=arr.length-1;j>0;j--) {
// swap(arr,0,j);
// buildHeap(arr,0,j);
// }
//
for (int i : arr) {
System.out.println(i);
}
}
/**
* 交换堆顶元素和末尾元素
*
* @param arr
* @param i 堆顶位置
* @param j 末尾位置
*/
private static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
/**
* 构建大顶堆 只要是大的就往上抛
*
* @param arr
* @param i 从下往上数第一个非叶子节点(从右往左),i每次定位都是父节点的位置
* @param length
*/
private static void buildHeap(int[] arr, int i, int length) {
int child;
// 构建大顶堆时,tmp最开始是从后往前数的第一个非叶子结点
for (; leftChild(i) < length; i = child) {
child = leftChild(i);
// 如果右结点大于左结点,child就变为右结点
// 注意顺序,先判断child的长度,再判断左右子树的大小
if (child < length - 1 && arr[child] < arr[child + 1]) {
child++;
}
// 如果左或右结点大于父节点,就和父结点交换
if (arr[child] > arr[i]) {
swap(arr, i, child);
} else {
break;
}
}
}
/**
* @param i
* @return 左孩子的位置
*/
private static int leftChild(int i) {
return 2 * i + 1;
}
}
4、归并排序
归并排序是递归算法一个好的实例,基本操作是合并两个已排序的表。
import java.util.Scanner;
/**
* 归并排序
* 合并两个已排序的数组
* @author thinkpad_ljj
*
*/
public class MergesSort {
public static void main(String[] args) {
Scanner read = new Scanner(System.in);
int n = read.nextInt();
int[] arr = new int[n];
for(int i = 0;i<n;i++) {
arr[i]=read.nextInt();
}
Mergesort(arr);
for (int i : arr) {
System.out.println(i);
}
}
private static void Mergesort(int[] arr) {
sort(arr,0,arr.length-1);
}
/**
* 排序,使用递归
* @param arr 待排序的数组
* @param left 左部分
* @param right 右部分
*/
private static int[] sort(int[] arr, int left, int right) {
int mid = (left+right)/2;
if(left<right) {
/*左边排序*/
sort(arr,left,mid);
/*右边排序*/
sort(arr,mid+1,right);
/*合并*/
merge(arr,left,mid,right);
}
return arr;
}
/**
* 合并数组
* 在合并的时候进行排序处理
* @param arr
* @param left
* @param mid
* @param right
*/
private static void merge(int[] arr, int left, int mid, int right) {
int i=left;
int j=mid+1;
int k=0;
int[] temp = new int[right - left + 1];
for(;i<=mid && j<=right;) {
if(arr[i]>arr[j]) {
temp[k++]=arr[j++];
}else {
temp[k++]=arr[i++];
}
}
/*比较完若数组还剩下运算,就直接加入到新数组当中*/
while(i<=mid) {
temp[k++]=arr[i++];
}
while(j<=right) {
temp[k++]=arr[j++];
}
for(int t = 0;t<temp.length;t++) {
arr[t+left] = temp[t];
}
}
}
5、快速排序
找出关键字,然后进行比较,比关键字大的排在右边,比关键字小的排在左边,这部分排好序后,接着继续分别对左半边以及右半边以同样的方式进行排序
import java.util.Scanner;
/**
* 快速排序
*
* @author thinkpad_ljj
*
*/
public class quickSort {
public static void main(String[] args) {
Scanner read = new Scanner(System.in);
int n = read.nextInt();
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = read.nextInt();
}
quickSort(arr, 0, arr.length - 1);
for (int i : arr) {
System.out.println(i);
}
}
private static void quickSort(int[] arr, int left, int right) {
if (left < right) {
int mid = getMidNum(arr, left, right);
quickSort(arr, left, mid - 1);
quickSort(arr, mid + 1, right);
}
}
/**
* 获得比较时的关键字
*
* @param arr
* @param left
* @param right
* @return
*/
private static int getMidNum(int[] arr, int left, int right) {
/* 数组的第一个数值作为关键字 */
int temp = arr[left];
while (left < right) {
/*要加上约束条件left<right,否则会溢出*/
while (left < right && arr[right] >= temp) {
right--;
}
arr[left] = arr[right];
while (left < right && arr[left] < temp) {
left++;
}
arr[right] = arr[left];
}
arr[left] = temp;
return left;
}
}
6、冒泡排序
每趟只比较两个相邻元素,每次都能把最大的元素“浮”出来。
private static void bubbleSort(int[] arr) {
int length = arr.length;
boolean change;
do {
change = false;
for (int i = 0; i < length-1; i++) {
if (arr[i] > arr[i + 1]) {
int temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
change = true;
}
length -= 1;
} while (change);
}
7、选择排序
基本思想:每次找出待排序数组中最小的数,与待排序数组的第一个数进行交换,接着继续比较,比如3,4 ,2,5,第一次排序就找出最小数2,接着和3进行交换-->2,4,3,5,再找出下一轮待排序中最小值为3,就和4进行交换-->2,3,4,5
/**
* 每次找出最小值,与待排序的首个元素进行交换
*
* @param arr
*/
private static void selectSort(int[] arr) {
int i;
int temp;
int k = 0;
/* 循环找出最小值 */
for (i = 0; i < arr.length; i++) {
k = i;
/* 循环找出最小值 */
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[k]) {
k = j;
}
}
/*与待排序的首个元素交换*/
temp = arr[k];
arr[k] = arr[i];
arr[i] = temp;
}
}
各排序的时间复杂度