// 外层循环控制从第几个数组元素开始
for (int i = 0; i < num.length - 1; i++) { // i<num. length-1,因为最后要用倒数第二个和最后一个比较
// i=0确定第一大的的数,并放到倒数第一位. i=1确定第二大的的数,并放到倒数第二位................
for (int j = 0; j < num.length - i - 1; j++) { // -i是因为最后一个已经是最大的,不需要再排
if (num[j] > num[j + 1]) {
// 通过引入变量a使前后交换顺序:1.把前面的num[j]交给一个变量a来记住;
// 2.把后面的num[j+1]赋值给num[j];3.把变量a赋值给num[j+1]
int a = num[j]; // 1.把前面的num[j]交给一个变量a来记住;
num[j] = num[j + 1]; // 2.把后面的num[j+1]赋值给num[j];
num[j + 1] = a; // 3.把变量a赋值给num[j+1]
}
}
}
// 插入排序
public static int[] insertionSort(int[] arr) {
int len = arr.length;
for (int i = 1; i < len; i++) {
// j表示当前元素的位置,将其和左边的元素比较,若当前元素小,就交换,也就相当于插入
// 这样当前元素位于j-1处,j--来更新当前元素,j一直左移不能越界,因此应该大于0
for (int j = i; j > 0 && arr[j] < arr[j - 1]; j--) {
int temp = arr[j]; // 元素交换
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
return arr;
}
// 分 与 和的方法 归并排序额外占用一个空间
public static 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, mid, right, temp);
}
}
// 合并的方法
/**
*
* @param arr 要排序的数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 做中转的数组
*/
public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;// 初始化i,左边有序序列的初始索引
int j = mid + 1;// 初始化j,右边有序序列的初始索引
int t = 0;// temp数组的指针,指向temp数组
// (一)
// 先把左右两边(有序的)数据按照规则填充到temp数组中
// 直到有一边处理完为止
while (i <= mid && j <= right) {
// 如果左边的元素小于右边的,将左边的拷贝到temp数组中
// 同时i和t后移
if (arr[i] < arr[j]) {
temp[t] = arr[i];
t++;
i++;
} else {// 反之,将右边的拷贝到temp中去
temp[t] = arr[j];
t++;
j++;
}
}
// (二)
// 把有剩余的一边全部拷贝到temp中去
while (i <= mid) {// 如果左边有剩余,将剩余的拷贝到temp中去
temp[t] = arr[i];
t++;
i++;
}
while (j <= right) {// 如果右边有剩余,将剩余的拷贝到temp中去
temp[t] = arr[j];
t++;
j++;
}
// (三)
// 将temp数组中的元素全部拷贝到arr中
// 并不是将所有的数据一下全部拷贝回去
t = 0;
int tempLeft = left;
System.out.println("tempLeft = " + tempLeft + " right = " + right);
System.out.println(Arrays.toString(temp));
while (tempLeft <= right) {
// 第一次合并tempLeft = 0,right = 1;//第二次合并:tempLeft = 2,right = 3
// 最后一次:tempLeft = 0,right = 7.
arr[tempLeft] = temp[t];
t++;
tempLeft++;
}
}
public static void quickSort(int[] arr, int left, int right) {
// 递归退出条件
if (left >= right) {
return;
}
int l = left;
int r = right;
// 其中array[left]并未发生改变,是r和l在变
while (r > l) {
while (r > l && arr[r] >= arr[left]) { // 从右向左
r--;
}
while (r > l && arr[l] <= arr[left]) { // 从左向右
l++;
}
if (r == l) { // 说明第一次快排结束
// 使基数(我们选的那个参照数,这里是指第一个数)到中间
//
int temp = arr[l];
arr[l] = arr[left];
arr[left] = temp;
} else {
// 引入变量temp作为中间值,使arr[l]和arr[r]交互
// 最终还是要进入到r==l,结束第一次快排
int temp = arr[r];
arr[r] = arr[l];
arr[l] = temp;
}
}
// 递归调用
quickSort(arr, left, l - 1);// 此时l和r相等
quickSort(arr, r + 1, right);
}
基数排序:稳定性排序,但是消耗的内存较大;对于正数使用,负数不适用
// 基数排序的方法
public static void radixSort(int[] arr) {
// 根据前面的推导,得到最终的代码
// 首先得到最大的数
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
// 判断最大的元素的有几位,将它转换成字符串
int maxLength = (max + "").length();
// 定义一个二位数组,表示10个桶,每个桶就是一个一维数组
// 说明
// 1、二维数组包含10个一维数组
// 2、为了防止在放入的时候,数据溢出,则每一个一维数组(桶),大小定为arr.length
// 3.很明确,基数排序是使用空间换时间的经典算法
int[][] bucket = new int[10][arr.length];
// 为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶每次放入的数据个数
// 可以这样理解:buckElementCounts[0]代表的就是第一个桶中存放了多少个数据
int[] bucketElementCounts = new int[10];
// 定义一个for循环
for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
// 针对每个元素的位数进行排序处理,第一次是个位,之后是十位。。。。。。。。
for (int j = 0; j < arr.length; j++) {
// 取出每个元素位数的值
int digitOfElement = arr[j] / n % 10;
// 放入到对应的桶中
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
// 按照这个桶的顺序(一维数组的下标依次取出数据,放入原来的数组中)
int index = 0;
for (int k = 0; k < bucketElementCounts.length; k++) {
// 如果桶内有数据,我们才放入到原数组
if (bucketElementCounts[k] != 0) {
// 循环第k个桶(即第k个一维数组),放入原数组中
for (int l = 0; l < bucketElementCounts[k]; l++) {
// 取出元素放入到arr中
arr[index++] = bucket[k][l];
}
}
// 第一轮处理后,将10个桶内寸的数据的个数的数据清零,即bucketElementCounts[k] = 0
bucketElementCounts[k] = 0;
}
}
}
// 选择排序
/**
* 原理: 第一轮比较:将第一个元素和后面的每一个元素比较,后面的哪一个元素比第一个元素小,则将他们交换位置,结果是数组的第一个元素为最小的
* 第二轮比较:以此类推,第二轮的结果是数组的第二个元素为第二小的元素 .......
*
* @param args
*/
// 选择排序的代码实现
public static void selectionSort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int index = i;// 将i记录下来,后面有用
for (int j = 1 + i; j < arr.length; j++) {
if (arr[index] > arr[j]) {
int temp = arr[index];
arr[index] = arr[j];
arr[j] = temp;
}
}
}
}
基于插入排序,但是不是很稳定
public static void shellSort(int[] str) {
if (str == null || str.length == 0) {
return;
}
for (int temp = str.length / 2; temp >= 1; temp /= 2) {
// 1.外边第一轮循环将0-->64比较,-4与-8,3与28,
// 外边第一轮结束后,数组变成了0 -8 3 64 -4 28
// 2.外边第二轮循环,将数组的第一个元素和第二个比较,若符合条件,则交换位置;
// 再将第二个元素和第三个比较,依此类推.....
for (int i = temp; i < str.length; i++) {
int flag = str[i];
int j = i - temp;
while (j >= 0) {
if (str[j] > flag) {
str[j + temp] = str[j];
j -= temp;
} else {
break;
}
}
str[j + temp] = flag;
}
}
}
未完待续...