1. 说明
这里的算法主要是自己这段时间为了面试复习而记录的,只符合自己的阅读习惯,且只是用代码实现了一下,并没有详细的原理介绍。
2. 常见的算法
面试时要会写如下五种常见的算法
2.1 冒泡排序
①、比较相邻的元素。如果第一个比第二个大,就交换他们两个。
②、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数(也就是第一波冒泡完成)。
③、针对所有的元素重复以上的步骤,除了最后一个。
④、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
时间复杂度为O(n^2)
2.2 快速排序(冒泡改进版)
①、先通过第一趟排序,将数组原地划分为两部分,其中一部分的所有数据都小于另一部分的所有数据。原数组被划分为2份
②、通过递归的处理, 再对原数组分割的两部分分别划分为两部分,同样是使其中一部分的所有数据都小于另一部分的所有数据。 这个时候原数组被划分为了4份
③、就1,2被划分后的最小单元子数组来看,它们仍然是无序的,但是它们所组成的原数组却逐渐向有序的方向前进。
④、这样不断划分到最后,数组就被划分为多个由一个元素或多个相同元素组成的单元,这样数组就有序了。
时间复杂度O(nlogn)
2.3 选择排序
①、从待排序序列中,找到关键字最小的元素
②、如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换
③、从余下的 N - 1 个元素中,找出关键字最小的元素,重复(1)、(2)步,直到排序结束
时间复杂度为O(n^2)
2.4 直接插入排序
直接插入排序基本思想是每一步将一个待排序的记录,插入到前面已经排好序的有序序列中去,直到插完所有元素为止
时间复杂度为O(n^2)
2.5 希尔排序(直接插入排序改进版)
是直接插入排序的改进,希尔排序通过加大插入排序中元素的间隔,并在这些有间隔的元素中进行插入排序,从而使数据项能够大跨度的移动。当这些数据项排过一趟序后,希尔排序算法减小数据项的间隔再进行排序,依次进行下去,最后间隔为1时,就是我们上面说的简单的直接插入排序。
时间复杂度为O(n^(1.3—2))
3. 代码实现
/**
* 1.冒泡排序 对比的次数是N-1次,两两比较,将最大的是挪到最后 经过N次排序,最后的N个数是有序的
* 要点:1.标识符,如果第一次没有变化,则是有序的 2.排序的次数length-1 3.第i次比较的范围 0到length-i(i从1开始)
*
* @param array 待排序的数组
* @return 排好序的数组
*/
public int[] bubbleSort(int[] array) {
for (int i = 1; i < array.length; i++) {
for (int j = 0; j < array.length - i; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
System.out.println("冒泡第" + i + "次排序的结果为");
display(array);
}
return array;
}
/**
* 2.选择排序 需要N-1轮比较 每一次都是讲最小的数选择出来,插入到当前需要排序的位置
* 要点:1.比较的轮数 len -1 2.每一轮待插入元素的位置 3.比较,如果该位置不是最小的数值,将最小的数和待排序的数对调
*
* @param array 待排序的数组
* @return 已经排好序的数组
*/
public int[] choiceSort(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
int min = i;
for (int j = i + 1; j < array.length; j++) {
if (array[j] < array[min]) {
min = j;
}
if (i != min) {
int temp = array[i];
array[i] = array[min];
array[min] = temp;
}
}
System.out.println("选择第" + i + "次排序的结果为");
display(array);
}
return array;
}
/**
* 3.直接插入排序
* 要点:首先要选择好待排序的那个数,在while循环中参与比较的数是temp,待比较的数
*
* @param array 倒排序的数组
* @return 排好序的数组
*/
public int[] straightInsert(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
int j = i + 1;
int temp = array[j];
while (j > 0 && temp < array[j - 1]) {
array[j] = array[j - 1];
j--;
}
array[j] = temp;
System.out.println("直接插入第" + i + "次排序的结果为");
display(array);
}
return array;
}
/**
* 4.快速排序-冒泡排序的改进版,原理是选择一个基准位,每一次元数组分成两部分,一部分比基准数大,另一部分比基准数小
* 注意:这个是简单版的快速排序,直接选择第一个数为基准数
* 以下例子利用了分治算法的快速排序,选择一个目标数字,将待排序的数组分成两个,
* 一部分都比这个数字大,一部分都比这个数字小
* <p>
* <p>
* 减少冒泡排序过程中比较的次数
*/
public void quickSort(int[] arr, int low, int high) {
int i, j, base, temp;
if (low > high) {
return;
}
i = low;
j = high;
//base是基准位,选择第一个数字为基准位
base = arr[low];
while (i < j) {
//先看右边,依次往左递减
while (base <= arr[j] && i < j) {
j--;
}
//再看左边,依次往右递增
while (base >= arr[i] && i < j) {
i++;
}
//如果条件满足则交换
if (i < j) {
temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
//最后将基准与i和j相等位置的数字调换,因为在上述交换的过程中,base上的数据肯定是不变的,也就是arr[low]不变
arr[low] = arr[i];
arr[i] = base;
//递归调用左半边
quickSort(arr, low, j - 1);
//递归调用右半边,因为数字J在的位置已经是有序的,所以不再参与排序
quickSort(arr, j + 1, high);
}
/**
* 2h的shell排序,是直接插入排序的改进,希尔排序通过加大插入排序中元素的间隔,并在这些有间隔的元素中进行插入排序,从而使数据项能够大跨度的移动。
*
* @param array
*/
public void shellSortFor2h(int[] array) {
int step;
int len = array.length;
for (step = len / 2; step > 0; step /= 2) {
for (int i = step; i < len; i++) {
int j = i;
int temp = array[j];
if (array[j] < array[j - step]) {
while (j - step >= 0 && temp < array[j - step]) {
array[j] = array[j - step];
j -= step;
}
array[j] = temp;
}
}
}
}
//遍历显示数组
public static void display(int[] array) {
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
AlgorithmInteview algorithmInteview = new AlgorithmInteview();
int[] array = {9, 8, 7, 6, 5, 4, 3, 2, 1, 1, 0};
//未排序数组顺序为
System.out.println("未排序数组顺序为:");
display(array);
System.out.println("-----------------------");
algorithmInteview.straightInsert(array);
System.out.println("-----------------------");
System.out.println("经过排序后的数组顺序为:");
display(array);
}