目录
3)时间复杂度分析:O( Nlog(N) ) - O(n^2)
一、冒泡排序
1)思路:
第i(i = 0,1,2,3,4,5...)个数比较【数组长度- 1 】次,每次循环确定一个最大/最小值,比较【数组长度 - 1 - i】次
2)代码实现:
static void sort(int a[]){
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1 - i; j++) {
// 交换
if(a[j] > a[j + 1]){
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
// 输出排序后的数组
System.out.println(Arrays.toString(a));
}
3)优化:
① 如果有序就不进行比较
static void sort1(int a[]){
// 是否进行了交换
boolean target = false;
for (int i = 0; i < a.length - 1; i++) {
for (int j = 0; j < a.length - 1; j++) {
// 交换
if(a[j] > a[j + 1]){
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
target = true;
}
if(!target){
continue;
}
}
}
// 输出排序后的数组
System.out.println(Arrays.toString(a));
}
② 控制循环次数
static void sort2(int a[]){
// 记录交换的最后一次
int count = a.length - 1;
while (true){
int num = 0;
for (int j = 0; j < count; j++) {
// 交换
if(a[j] > a[j + 1]){
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
num = j;
}
}
count = num;
// 如果最后一次交换下标为0,退出
if(count == 0)
break;
}
// 输出排序后的数组
System.out.println(Arrays.toString(a));
}
4)时间复杂度分析:O(n^2)
二、选择排序
1)思路:
第一次从arr[0] ~ arr[n - 1]中选取最小值,和arr[0]交换、第二次从arr[1] ~ arr[n - 1]中选取最小值,和arr[1]交换、第i次从arr[i - 1] ~ arr[n - 1]中选取最小值,和arr[i - 1]交换
2)代码:
public static void choiceSort(int arr[]) {
// 最小数
int min = 0;
// 最小数的下标
int minIndex = 0;
// 是否交换
boolean isFlag = false;
for (int i = 0; i < arr.length; i++) {
// 最小的值默认为当前值
min = arr[i];
// 最小下标默认为当前值的下标
minIndex = i;
for (int j = i + 1; j < arr.length; j++) {
// 找到最小值
if (arr[j] < min) {
min = arr[j];
minIndex = j;
isFlag = true;
}
}
// 如果没交换,则代表有序
if (!isFlag) break;
arr[minIndex] = arr[i];
arr[i] = min;
}
System.out.println(Arrays.toString(arr));
}
3)时间复杂度分析:O( n^2)
三、插入排序
1)思路:
构建有序序列,每次在未排序数组中取出一个数据,与有序序列中的数据进行比较,找到合适的位置插入。
2)代码:
// 插入排序
public static void insertSort(int[] arr){
for (int i = 1; i < arr.length; i++){
// 存储要插入的数
int insertVal = arr[i];
// 要比较的下标
int insetIndex = i - 1;
while (insetIndex >= 0 && insertVal < arr[insetIndex]){
arr[insetIndex + 1] = arr[insetIndex];
insetIndex--;
}
// 插入操作
arr[insetIndex + 1] = insertVal;
}
System.out.println(Arrays.toString(arr));
}
3)时间复杂度分析:O(n^2)
四、希尔排序--移位法(推荐使用)
1)思路:
把记录按下标的一定增量(gap)进行分组,对每组使用直接插入排序算法排序,增量每次递减,当增量减至1时,整个文件被分为一组,变成一组有序数据。
移位法:
// 先保存原数据
int insertVal = arr[i];
// 移动
arr[i] = arr[i - gap];
// 赋值
arr[i - gap] = insertVal;
2)代码:
// 希尔排序--移位法
public static void shellSort2(int[] arr){
// 循环次数(步长每次/2)
for (int gap = arr.length / 2; gap > 0; gap /= 2){
// 需要比较的组数
for (int i = gap; i < arr.length; i++) {
// 保存原数据
int insertVal = arr[i];
// 从小到大排序,如果后一个数大于前一个数,则无需比较
if(arr[i] < arr[i - gap]){
// 移动
arr[i] = arr[i - gap];
// 赋值
arr[i - gap] = insertVal;
}
}
}
System.out.println(Arrays.toString(arr));
}
3)时间复杂度分析:O( Nlog(N) )
五、希尔排序--交换法(不推荐使用)
1)思路:
把记录按下标的一定增量(gap)进行分组,对每组使用直接插入排序算法排序,增量每次递减,当增量减至1时,整个文件被分为一组,变成一组有序数据。
交换法:
int temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = arr[i];
2)代码:
// 希尔排序--交换法
public static void shellSort1(int[] arr){
int temp = 0;
// 循环次数(步长每次/2)
for (int gap = arr.length / 2; gap > 0; gap /= 2){
// 需要比较的组数
for (int i = gap; i < arr.length; i++) {
// 每组比较的数
for (int j = i - gap; j >= 0; j -= gap) {
// 交换
if(arr[j] > arr[j + gap]){
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
}
System.out.println(Arrays.toString(arr));
}
3)时间复杂度分析:O( Nlog(N) )
六、快速排序
1)思路:
① 确定分界点x(一般是取左端点、右端点、一半 )
②
调整范围( * 重点 * )使得左边区域所有的数都<=x,右边区域所有的数都>=x
③ 递归处理左右两段
2)代码:
static void quick_sort(int q[], int l, int r){
//如果数组中没有数据,或者只有一个数据,则不用进行排序操作
if (l >= r) return;
//左右指针的初始位置,分界点的位置
int i = l - 1, j = r + 1, x = q[l+r >> 1];
while (i < j) {
do i++; while (q[i] < x);
do j--; while (q[j] > x);
if(i < j) {
int temp = q[i];
q[i] = q[j];
q[j] = temp;
}
}
quick_sort(q, l, j);
quick_sort(q, j+1, r);
}
3)时间复杂度分析:O( Nlog(N) ) - O(n^2)
七、归并排序
1)思路:
利用归并思想实现的排序算法,采用经典的分治策略将一个问题拆分成一些小的问题(分),然后递归求解,求解后将各个小问题的答案合并在一起(治)。
2)代码:
static void merge_sort(int q[], int l, int r){
if(l >= r) return;
int mid = l+r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int k = 0, i = l, j = mid + 1;
int tmp[] = new int[r - l + 1];
while (i <= mid && j <= r){
if(q[i] <= q[j]) tmp[k++] = q[i++];
else tmp[k++] = q[j++];
}
while(i <= mid) tmp[k++] = q[i++];
while(j <= r) tmp[k++] = q[j++];
for (i = l, j = 0; i <= r; i++, j++)
q[i] = tmp[j];
}
3)时间复杂度分析:O( Nlog(N) )
八、基数排序(桶排序)
1)思路:
将整数按位切割成0-9之间的数字,放在不同的桶(二维数组bucket[][])中,按位比较每个数大小,循环原数组中数字长度最大个次数。
2)代码:
// 基数排序
public static void radixSort(int[] arr){
// 定义二维桶
int[][] bucket = new int[10][arr.length];
// 定义每个桶中存放有多少数据
int[] bucketCount = new int[10];
// 求出最大值
int maxNum = arr[0];
for (int i = 0; i < arr.length; i++) {
if(maxNum < arr[i]) maxNum = arr[i];
}
// 求出最大值的位数
int maxLength = (maxNum + "").length();
// 循环
for (int i = 0, n = 1; i < maxLength; i++, n *= 10){
for (int j = 0; j < arr.length; j++){
// 求出各位数
int num = arr[j] / n % 10;
// 放入桶中,并记录每个桶中数据的个数
bucket[num][bucketCount[num]++] = arr[j];
}
int index = 0;
// 取出每轮的数据
for (int k = 0; k < bucketCount.length; k++) {
if(bucketCount[k] != 0){
for (int m = 0; m < bucketCount[k]; m++) {
// 取出数据,放入原数组中
arr[index++] = bucket[k][m];
}
}
// 将记录每个桶中数据存放个数的数组置为空,以便下次使用
bucketCount[k] = 0;
}
}
System.out.println(Arrays.toString(arr));
}
3)时间复杂度分析:O( Nlog(N) )
九、堆排序
1)思路:
① 将待排序的序列构造成一个大顶堆或小顶堆
② 此时,整个序列的最大值或最小值就是堆顶的跟结点
③ 将其与末尾元素进行交换,此时末尾就是最大值
④ 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的此小值,反复执行,便能得到一个有序序列
2)代码:
/**
* 堆排序
* @param arr 要排序的数组
*/
public static void heapSort(int arr[]) {
int temp = 0;
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adJustHeap(arr, i, arr.length);
}
for (int i = arr.length - 1; i > 0; i--) {
// 交换
temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
adJustHeap(arr, 0 , i);
}
System.out.println(Arrays.toString(arr));
}
/**
* 将一个数组调整成一个大顶堆
* @param arr 数组
* @param i 从哪个位置调整
* @param length 长度
*/
public static void adJustHeap(int[] arr, int i, int length) {
// 先取出当前元素,保存在临时变量
int temp = arr[i];
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
if (k+1 < length && arr[k] < arr[k + 1]) k++;
if (arr[k] > temp) {
arr[i] = arr[k];
i = k;
} else {
break;
}
}
// 当for循环结束后,已经将以i为父节点的树的最大值放在了顶部
arr[i] = temp;
}