一、插入排序
稳定排序
模板
class Sort {
public static <AnyTpye extends Comparable<? super AnyTpye>> void insertionSort(AnyTpye[] a){ //Comparable可以比较的数或对象
int j;
for (int p =1;p < a.length;p++){ //默认a[0]是有序的,所以从1开始
AnyTpye tmp = a[p]; //暂存要插入的p号元素
//把p号元素从本身开始往前比较,直到比前一个数大,终止循环,可以插入
for (j = p;j>0 && tmp.compareTo(a[j-1])<0;j--)
a[j] = a[j-1];
a[j] = tmp;
}
}
}
应用
import java.util.Arrays;
class Sort{
public static void insertionSort(int[] a){
int j;
for (int p = 1; p < a.length; p++) {
int tmp = a[p];
for (j = p;j>0 && tmp<a[j-1];j--){
a[j] = a[j-1];
}
a[j] = tmp;
}
}
public static void main(String[] args) {
int[] nums = {8,34,64,51,32,21};
insertionSort(nums);
System.out.println(Arrays.toString(nums));
}
}
分析
时间复杂度O(N^2)
N个互异数的数组的平均逆序数是N(N-1)/4
通过交换相邻元素进行排序的任何算法平均都需要Ω(N^2)
时间
二、希尔排序
非稳定排序
模板
class Sort{
public static <AnyTpye extends Comparable<? super AnyTpye>> void shellSort(AnyTpye[] a){
int j;
//在不同的gap上用插入排序
for (int gap = a.length/2;gap > 0;gap /= 2)
for (int i = gap;i < a.length;i++){
AnyTpye tmp = a[i];
for (j = i;j>=gap && tmp.compareTo(a[j-gap])<0;j -= gap)
a[j] = a[j-gap];
a[j] = tmp;
}
}
}
应用
import java.util.Arrays;
class Sort{
public static void shellSort(int[] a){
int j;
for (int gap = a.length/2;gap > 0;gap /= 2){
for (int i = gap;i < a.length;i++){
int tmp = a[i];
for (j = i;j >= gap && tmp < a[j-gap];j -= gap){
a[j] = a[j-gap];
}
a[j] = tmp;
}
}
}
public static void main(String[] args) {
int[] nums = {8,34,64,51,32,21};
shellSort(nums);
System.out.println(Arrays.toString(nums));
}
}
分析
使用希尔增量({1,4,8...,2^k}
)的希尔排序,最坏时间复杂度O(N^2)
使用 Hibbard 增量({1,3,7,...2^k-1}
)的希尔排序,最坏时间复杂度O(N^1.5)
,它跟希尔增量的区别在于相邻增量没有公因数
最优的增量序列:{1,5,19,41,109,...,9*(4^k-2^k)+1,4^i-3*2^i+1,...}
三、选择排序
import java.util.Arrays;
class Sort{
private static void chooseSort(int[] nums){
for (int i = 0; i < nums.length-1; i++) {
int k = i;
for (int j = i+1; j < nums.length; j++) {
if (nums[k] > nums[j]) k = j; //选出最小数的角标
}
if (k!=i){ //最小的不是自己则需要拿到前面
int tmp = nums[i];
nums[i] = nums[k];
nums[k] = tmp;
}
}
}
public static void main(String[] args) {
int[] nums = {8,34,64,51,32,21};
chooseSort(nums);
System.out.println(Arrays.toString(nums));
}
}
四、堆排序
完全二叉树,第 i 个结点为例,左孩子为 2i+1,右孩子为 2i+2
public class HeapSort {
public static void main(String[] args) {
// int[] arr = {5, 1, 7, 3, 1, 6, 9, 4};
int[] arr = {16, 7, 3, 20, 17, 8};
heapSort(arr);
for (int i : arr) {
System.out.print(i + " ");
}
}
//创建堆
private static void heapSort(int[] arr) {
//创建堆
for (int i = (arr.length - 1) / 2; i >= 0; i--) {
//从第一个非叶子结点从下至上,从右至左调整结构
adjustHeap(arr, i, arr.length);
}
//调整堆结构+交换堆顶元素与末尾元素
for (int i = arr.length - 1; i > 0; i--) {
//将堆顶元素与末尾元素进行交换
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
//重新对堆进行调整,调前i个就行了
adjustHeap(arr, 0, i);
}
}
//调整堆
private static void adjustHeap(int[] arr, int parent, int length) {
//将temp作为父节点
int temp = arr[parent];
//左孩子
int lChild = 2 * parent + 1;
while (lChild < length) {
//右孩子
int rChild = lChild + 1;
// 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点
if (rChild < length && arr[lChild] < arr[rChild]) {
lChild++;
}
// 如果父结点的值已经大于孩子结点的值,则直接结束
if (temp >= arr[lChild]) {
break;
}
// 把孩子结点的值赋给父结点
arr[parent] = arr[lChild];
//选取孩子结点的左孩子结点,继续向下筛选
parent = lChild;
lChild = 2 * lChild + 1;
}
arr[parent] = temp;
}
}
五、冒泡排序
import java.util.Arrays;
class Sort{
private static void chooseSort(int[] nums){
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < nums.length - i - 1; j++) {
if (nums[j] > nums[j+1]){
int tmp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = tmp;
}
}
}
}
public static void main(String[] args) {
int[] nums = {8,34,64,51,32,21};
chooseSort(nums);
System.out.println(Arrays.toString(nums));
}
}
六、快速排序
import java.util.Arrays;
class Sort{
private static void quickSort(int[] nums){
quickSort(nums, 0, nums.length - 1);
}
private static void quickSort(int[] nums, int l, int r) {
if (l >= r) return;
int index = helper(nums,l,r);
quickSort(nums,l,index-1);
quickSort(nums,index+1,r);
}
private static int helper(int[] nums,int l,int r){
int i = l;
int j = r;
int x = nums[i];
while (i < j){
while (i < j && nums[j] >= x){
j--;
}
if (i < j){
nums[i] = nums[j];
}
while (i < j && nums[i] <= x){
i++;
}
if (i < j){
nums[j] = nums[i];
}
}
nums[i] = x;
return i;
}
public static void main(String[] args) {
int[] nums = {8,34,64,51,32,21};
quickSort(nums);
System.out.println(Arrays.toString(nums));
}
}
七、归并排序
import java.util.Arrays;
class Sort{
private static void mergeSort(int[] nums){
mergeSort(nums,0,nums.length-1);
}
private static void mergeSort(int[] nums, int left, int right) {
if (left < right){
int center = (left + right) / 2;
mergeSort(nums,left,center); //递归调用
mergeSort(nums,center+1,right);
merge(nums,left,center,right); //连接两个有序数组
}
}
private static void merge(int[] nums, int left, int center, int right) {
int[] tmpNums = new int[nums.length];
int mid = center + 1; //后边数组的开始
int third = left;
int tmp = left; //留到最后拷贝数组用
while (left <= center && mid <= right){
if (nums[left] <= nums[mid]){
tmpNums[third++] = nums[left++];
}else {
tmpNums[third++] = nums[mid++];
}
}
while (mid <= right){
tmpNums[third++] = nums[mid++];
}
while (left <= center){
tmpNums[third++] = nums[left++];
}
while (tmp <= right){
nums[tmp] = tmpNums[tmp++];
}
}
public static void main(String[] args) {
int[] nums = {8,34,64,51,32,21};
mergeSort(nums);
System.out.println(Arrays.toString(nums));
}
}
八、基排序
public class RadixSort {
public static void main(String[] args) {
int[] arr = {63, 157, 189, 51, 101, 47, 141, 121, 157, 156,
194, 117, 98, 139, 67, 133, 181, 12, 28, 0, 109};
radixSort(arr);
System.out.println(Arrays.toString(arr));
}
private static void radixSort(int[] arr) {
//待排序列最大值
int max = arr[0];
int exp;//指数
//计算最大值,确定最高位数
for (int anArr : arr) {
if (anArr > max) {
max = anArr;
}
}
//从个位开始,对数组进行排序
for (exp = 1; max / exp > 0; exp *= 10) {
//存储待排元素的临时数组
int[] temp = new int[arr.length];
//分桶个数
int[] buckets = new int[10];
//将数据出现的次数存储在buckets中
for (int value : arr) {
//(value / exp) % 10 :value的最底位(个位)
buckets[(value / exp) % 10]++;
}
//更改buckets[i],
for (int i = 1; i < 10; i++) {
buckets[i] += buckets[i - 1];
}
//将数据存储到临时数组temp中
for (int i = arr.length - 1; i >= 0; i--) {
temp[buckets[(arr[i] / exp) % 10] - 1] = arr[i];
buckets[(arr[i] / exp) % 10]--;
}
//将有序元素temp赋给arr
System.arraycopy(temp, 0, arr, 0, arr.length);
}
}
}