记录数据结构中典型的排序算法
[TOC]
1 冒泡排序(稳定)
思想:每趟比较将当前数列未排序部分的最大的元素“沉”到数列末端,而小的元素会经由交换慢慢“浮”到数列的顶端。
1 | public void sort(int[] arr) { |
2 | for (int i = 0; i < arr.length; i++) { |
3 | boolean flag = false;//记录是否发生交换,若一次遍历未发生交换,则数组已经有序 |
4 | for (int j = 0; j < arr.length - i - 1; j++) {//每次比较相邻的元素,较大者上浮 |
5 | if (arr[j + 1] < arr[j]) { |
6 | swap(arr, j, j + 1); |
7 | flag = true; |
8 | } |
9 | } |
10 | if (!flag) break; |
11 | } |
12 | } |
2 选择排序(不稳定)
思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕
1 | public void sort(int[] arr) { |
2 | for (int i = 0; i < arr.length - 1; i++) { |
3 | int min_index = i;//每次循环找最小 |
4 | for (int j = i + 1; j < arr.length; j++) { |
5 | if (arr[min_index] > arr[j]) |
6 | min_index = j; |
7 | } |
8 | swap(arr, min_index, i);//交换 |
9 | } |
10 | } |
3 插入排序(不稳定)
思想:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
1 | public void sort(int[] arr) { |
2 | for (int i = 1; i < arr.length; i++) {//[0,i-1]未有序序列 |
3 | int cur = arr[i], index = i - 1; |
4 | while (index >= 0 && cur < arr[index]) { |
5 | arr[index + 1] = arr[index]; |
6 | index--; |
7 | } |
8 | arr[index + 1] = cur; |
9 | } |
10 | } |
4 快速排序(不稳定)
思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
记当前值为a,从右边找出比a小的元素,左边找到比a大的元素,交换,直到左右两索引相遇,此时,a左边值均小于a,右边均大于a,递归的执行
1 | public void sort(int[] arr, int begin, int end) { |
2 | if (begin >= end) return;//递归结束条件 |
3 | int cur = arr[begin]; |
4 | int i = begin, j = end; |
5 | while (i < j) { |
6 | while (i < j && arr[j] >= cur) j--;//右边找小于cur的 |
7 | while (i < j && arr[i] <= cur) i++;//左边找大于cur的 |
8 | if (i > j) break;//若当前i>j直接break |
9 | swap(arr, i, j);//交换 |
10 | } |
11 | arr[i] = cur;//将当前值(基准)移到i中 |
12 | sort(arr, begin, i - 1);//递归左半部分 |
13 | sort(arr, i + 1, end);//递归右半部分 |
14 | } |
5 归并排序(稳定)
思想:分治n->n/2->…->1,再依次归并
1 | private void sort(int[] arr, int left, int right) { |
2 | if (left < right) { |
3 | int mid = left + (right - left) / 2;//分治 |
4 | sort(arr, left, mid);//处理[left,mid] |
5 | sort(arr, mid + 1, right);//处理[mid+1,right] |
6 | merge(arr, left, mid, right);//归并核心 |
7 | } |
8 | |
9 | } |
10 | //将[left,mid]和[mid+1,right]两个区间的数进行合并,利用temp数组存储合并后的结果 |
11 | //将归并后的结果依次放到原数组的[left,right]位置 |
12 | private void merge(int[] arr, int left, int mid, int right) { |
13 | int[] temp = new int[right - left + 1]; |
14 | int i = left, j = mid + 1, index = 0; |
15 | while (i <= mid && j <= right) { |
16 | if (arr[i] <= arr[j]) { |
17 | temp[index++] = arr[i++]; |
18 | } else { |
19 | temp[index++] = arr[j++]; |
20 | } |
21 | } |
22 | while (i <= mid) |
23 | temp[index++] = arr[i++]; |
24 | while (j <= right) |
25 | temp[index++] = arr[j++]; |
26 | for (int k = 0; k < temp.length; k++) |
27 | arr[left + k] = temp[k];//结果要与原数组[left,right]位置对应 |
28 | } |
6 堆排序(不稳定)
思想: 三步:1 建初始堆(大\小根堆) 2交换 3 调整堆
1 | /** 1 建初始堆(大根堆) |
2 | * 2 交换arr[0]和arr[i] |
3 | * 3 调整堆 |
4 | **/ |
5 | private void sort(int[] arr) { |
6 | int begin = (arr.length - 2) / 2; |
7 | for (int i = begin; i >= 0; i--)//init heap |
8 | adjust_heap(arr, i, arr.length); |
9 | for (int i = arr.length - 1; i >= 0; i--) { |
10 | swap(arr, i, 0);//swap |
11 | adjust_heap(arr, 0, i);//adjust_heap |
12 | } |
13 | } |
14 | private void adjust_heap(int[] arr, int begin, int length) { |
15 | int temp = arr[begin]; |
16 | for (int i = 2 * begin + 1; i < length; i = 2 * i + 1) { |
17 | if (i + 1 < length && arr[i + 1] > arr[i]) |
18 | i++; |
19 | if (arr[i] <= temp) break; |
20 | arr[begin] = arr[i]; |
21 | begin = i; |
22 | } |
23 | arr[begin] = temp; |
24 | } |