目录
算法一,冒泡排序:
特点:第一次排序之后最大的数总是在最后一个,第二次排序除了最后一位最大的数排在倒数第二位
例:
代码实现:
int[] arr = {1,5,-1,-5,6,-8};
int temp = 0;
//数组有n个值,只需要循环n-1次
for (int i = 0; i < (arr.length - 1); i++) {
boolean flag = false;
//每次排序之后,最大的数已经在最后,这个数不用参加循环,所以每次循环,次数都要再减1
for (int j = 0; j < (arr.length - 1 - i); j++) {
if (arr[j] > arr[j + 1]){
//如果进入if则代表有交换
flag = true;
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
System.out.println(Arrays.toString(arr));
if (!flag){
return;
}
}
System.out.println(Arrays.toString(arr));
算法二:选择排序
特点,每次选择数组中最小的数,和arr[ i ]交换,每一轮排序之后,最小的数总是在最前面
例子:
public static int[] get(int[] arr){
//一共需要循环数组长度-1次
for (int i = 0; i < (arr.length - 1); i++) {
//设置下标为i 因为每到此循环说明已经遍历了一次,原有下标对应的值已经找到
index = i;
//假设temp的值都为下标对应的值
temp = arr[index];
//i + 1说明不和自身作比较
for (int j = i + 1; j <= arr.length; j++) {
if (arr[index] > arr[j]){
//如果进入此条件,说明满足交换原则
index = j;
temp = arr[j];
}
}
//开始交换
arr[index] = arr[i];
arr[i] = temp;
System.out.println(Arrays.toString(arr));
}
return arr;
}
算法三:插入排序
把数组元素分为两个集合,第一个集合为有序,第二个集合为无序,每次从无序中取第一个元素和有序的第一个元素比较,如果大,则比第二个比较,只到遇到一个小于的值,插入。
例子:
代码实现:
int[] arr = {1,5,-1,-5,6,-8};
for (int i = 1; i < arr.length; i++) {
//下标,初始值为有序数组的最后一个
int index = i - 1;
//定义的最小值,初始值为无序数组的第一个
int min = arr[i];
//参数一:防止数组下标越界
//参数二:如果定义的最小值(无序数组第一个)小于有序数组的最后一个
while (index >= 0 && min < arr[index]){
//交换位置
//例: 1,-1 交换之后成为 1,1
arr[index + 1] = arr[index];
index--;
}
//赋值,将目标值移到有序数组
arr[index + 1] = min;
}
System.out.println(Arrays.toString(arr));
算法四:希尔排序
通过两次划分,把不同的元素划分为不同的组,最后再合并,即可得到按照顺序排列的数组
例子:
代码实现:
代码之一:交换法
/**
* 交换法
*/
public class Shell {
public static void main(String[] args) {
int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
int temp = 0;
int length = arr.length / 2;
while (length >= 1){
for (int i = length; i < arr.length; i++) {
//由于i是从高位慢慢变向地位,所以当循环时,j -= length表示,从数组下标高的开始,向数组下标低的比较
for (int j = i - length; j >= 0; j -= length){
if (arr[j] > arr[j + length]){
temp = arr [j + length];
arr[j + length] = arr[j];
arr[j] = temp;
}
}
}
//每次遍历长度减半
length = length / 2;
System.out.println(Arrays.toString(arr));
}
System.out.println(Arrays.toString(arr));
}
}
代码之二,移位法
//移位法
public int[] shell(int[] arr) {
int length = arr.length / 2;
while (length >= 1) {
for (int i = length; i < arr.length; i++) {
int j = i;
int temp = arr[j];
while (j - i > 0 && temp < arr[j - i]) {
//开始移位例: 9,8,7,6,5,4,3,2,1,0 移位之后变成9,8,7,6,5,9,3,2,1,0
arr[j] = arr[j - i];
//减去步长
j = j - i;
}
//到这一步就是找到了,将temp的值赋值给最前面的
//如上一步的数组,复制之后就变成了4,8,7,6,5,9,3,2,1,0
arr[j] = temp;
}
length = length / 2;
}
return arr;
}
算法五:快速排序
选取一个数作为基准,比这个数小的放在左面,比这个数大的放在右面,再以划分的两个数组中的一个数为基准,重复划分。。本质就是递归
图解:
代码实现:
public void quickSort(int[] arr,int left,int right){
int l =left;
int r = right;
int middle = arr[(left + right) / 2];
int temp = 0;
while (l < r){
//如果左边的数小于中间的数,就往前移位,如果不满足这个条件,就是找到了
while (arr[l] < middle){
l += 1;
}
//如果右边的数小于中间的数,就往后移位,如果不满足这个条件,就是找到了
while (arr[r] > middle){
r -= 1;
}
//两者相等,说明遍历完
if (l >= r){
break;
}
temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
//不会出现死循环(不理解)
if (arr[l] == middle){
r -= 1;
}
//不会出现死循环(不理解)
if (arr[r] == middle){
l += 1;
}
System.out.println(Arrays.toString(arr));
}
//两者相等,跨过相等的数,继续遍历 不然会出现死循环
//这里使l++,r--是为了让middle包含进去,如果是l--,r++,则middle不包含在其中
if (l == r){
l++;
r--;
}
//向左遍历
if (left < r){
quickSort(arr,left,r);
}
//向右遍历
if (right > l){
quickSort(arr,l,right);
}
}
算法六: 归并排序
把排序的数组分为若干个数字,再把这些数字合并为数组。使用了分治算法的思想,然后使用递归算法合并为有顺序的数组
图解:
代码实现:
//代码调用
int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
int[] temp = new int[arr.length];
GuiBing guiBing = new GuiBing();
guiBing.mergeSort(arr, 0, arr.length - 1, temp);
//分+合的方法
public void mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
//向左分解
mergeSort(arr, left, mid, temp);
//向右分解
mergeSort(arr, mid + 1, right, temp);
merge(arr, left, right, mid, temp);
}
}
/**
* 合并的方法
*
* @param arr 排序初始数组
* @param left 左下标
* @param right 右下标
* @param mid 中间索引
* @param temp 中转数组
*/
public void merge(int[] arr, int left, int right, int mid, int[] temp) {
int l = left;
int j = mid + 1;
int t = 0; //做temp的索引
while (l <= mid && j <= right) {
if (arr[l] <= arr[j]) {
temp[t] = arr[l];
t += 1;
l += 1;
} else {
temp[t] = arr[j];
t += 1;
j += 1;
}
}
//将还存在arr中的数取出
while (j <= right) {
temp[t] = arr[j];
t += 1;
j += 1;
}
while (l <= mid) {
temp[t] = arr[l];
t += 1;
l += 1;
}
//将temp中的数据拷贝到arr中
int tempLeft = left;
t = 0;
while (tempLeft <= right) {
arr[tempLeft] = temp[t];
tempLeft += 1;
t += 1;
}
System.out.println(Arrays.toString(arr));
}
算法七: 基数排序
将待排序数组按照个位从高到低,十位从高到低,百位从高到低。。。的顺序一次放入十个桶中,每个桶有相应的下标。该排序最大循环次数为最大的数的位数。
图解:
代码实现:
public static void main(String[] args) {
int[] arr = {53, 3, 542, 748, 14, 214};
sort(arr);
}
//算出数组最大值
public static int max(int[] arr) {
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
return max;
}
//算出最大值的数是几位数
public static int maxIndex(int max) {
int index = 0;
if (max != 0) {
index++;
max = max % 10;
}
return index;
}
public static void sort(int[] sort) {
//二维数组代表桶 有十个桶
int[][] arr = new int[10][sort.length];
//一维数组是记录二位数字每个桶中有几个数
int[] arrCounts = new int[10];
int temp = 0;
int max = max(sort);
int num = maxIndex(max);
boolean flag = true;
while (flag) {
for (int i = 0; i < sort.length; i++) {
if (i != 0){
temp = (sort[i] / (10 * i)) % 10;
}else{
temp = sort[i] % 10;
}
//arrCounts[temp] 刚开始为0,代表第temp个桶的第一个数是sort[i]
arr[temp][arrCounts[temp]] = sort[i];
arrCounts[temp]++;
}
int index = 0;
for (int i = 0; i < arrCounts.length; i++) {
if (arrCounts[i] != 0) {
for (int j = 0; j < arrCounts[i]; j++) {
sort[index] = arr[i][j];
index++;
}
}
//每次赋值结束之后要清零
arrCounts[i] = 0;
}
num--;
if (num <= 0) {
System.out.println(Arrays.toString(sort));
flag = false;
}
}
}
算法八: 堆排序
public static void sort(){
for (int i = arr.length / 2 - 1; i >= 0; i--) {
largeSort(arr,i,arr.length);
}
System.out.println(Arrays.toString(arr));
for (int j = arr.length - 1; j > 0; j--) {
int temp = 0;
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
largeSort(arr,0,j);
}
}
/**
*
* @param arr 传入的数组
* @param i 非叶子节点在数组中的索引
* @param length 数组长度
*/
public static void largeSort(int[] arr,int i,int length){
int temp = arr[i];
for (int j = (2 * i + 1); j < length; j = (j * 2 + 1)) {
//如果左节点比右节点小
if (arr[j] < arr[j + 1] && j + 1 < length){
j++;
}
//如果节点比头节点大
if (arr[j] > temp){
//把叶子节点的值赋给头节点
arr[i] = arr[j];
//下标后移
i = j;
}
else {
break;
}
}
//将arr[i]这个值给最后一位
arr[i] = temp;
}