快速排序
我的理解:每次排序都能确定当前基准的位置。
代码实现:
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
int[] arr = {3,6,4,5,9,0,2};
quickSort(arr,0,arr.length-1);
}
public static void quickSort(int[] arr, int begin, int end) {
int i= begin;//左指针
int j = end;//右指针
int key = arr[i];//设第一个数字为基准
//从右侧开始查找比基准小的数字
while (i<j) {//每个循环中最多执行一次,左指针所在的数值交换+右指针所指向的数值交换。
while (j>i&&arr[j]>key) j--;
if (i<j) {//交换
arr[i] = arr[j];
i++;
}
//从右侧开始查找比基准大的数字
while (i<j&& arr[i]<key) i++;
if (i<j) {
arr[j] = arr[i];
j--;
}
}
//基准赋值给他应该在的位置
arr[i] = key;
System.out.println(Arrays.toString(arr));
if (i-begin>1) {//基准左侧数组的长度大于1的时候对左侧数组排序
quickSort(arr, begin, i);
}
if (end-i>1) {//基准右侧数组的长度大于1的时候对左侧数组排序
quickSort(arr, i+1, end);
}
}
}
直接选择排序
我的理解:
每次遍历整个数组,找出最大或最小值,依次排列。他和冒泡排序的区别在于选择排序记录最大元素下标,一次for循环后交换数值,冒泡排序每做一次比较就交换一次数值。
代码实现:
public static void directChooseSort(int[] arr) {
for(int i=0; i<arr.length; i++){
int maxIndex = i;//从第i位元素开始比较,假设其为最大元素的下标
for(int j=i+1; j<arr.length; j++){
if (arr[j] > arr[i]) {//记录较大元素的下表
maxIndex = j;
}
}
//将第i位元素与最大元素交换
int temp = arr[maxIndex];
arr[maxIndex] = arr[i];
arr[i]= temp;
}
System.out.println(Arrays.toString(arr));
}
堆排
我的理解:
1.先构造大顶堆,
2.交换数组中第一个(也就是最大的元素)和最后一个元素(为了取出最大的元素)。
3.再从第一个元素(对应树中的根节点)构造大顶堆,不考虑最后一个元素所在的节点。
4.循环2 3步
代码实现:
private static int len;//做排序的时候用到
public static void main(String[] args) {
int[] arr = {3,6};
len = arr.length;
//构造大顶堆
for(int i=(int) Math.floor(arr.length/2)-1;i>=0;i--){
heapChange(arr, i);
}
System.out.println(Arrays.toString(arr));
for (int i = arr.length-1; i > 0 ; i--) {
swap(arr, i, 0);
len--;//刚交换的节点不参与比较
heapChange(arr, 0);
}
System.out.println(Arrays.toString(arr));
}
//构造大顶堆
public static void heapChange(int[] arr, int i) {
int s = 2*i;
if(s<len){//防止递归的时候数组越界
int key = arr[i];
int tempMaxIndex = 0;//默认值是0
boolean changeFlag = false;//保证正确求得左右子树中较大者,而不是根节点
//二者选其大
if (s+2<len) {//小于总长度的时候做比较,防止数组越界,此条件下父节点有左右两个子节点
if (arr[s+1] > arr[s+2]) {
tempMaxIndex = s+1;
changeFlag = true;
}else{
tempMaxIndex = s+2;
changeFlag = true;
}
}else if (s+1<len) {//父节点只有左子节点
tempMaxIndex = s+1;
changeFlag = true;
}
//key与大者比较交换,交换完成后,对交换的左节点或右节点进行构造大顶堆
if(changeFlag && key<arr[tempMaxIndex]){
System.out.println("比较");
swap(arr, tempMaxIndex, i);
heapChange(arr, tempMaxIndex);
}
}
}
//交换方法
public static void swap(int[] arr,int i,int c) {
int temp;
temp = arr[i];
arr[i] = arr[c];
arr[c] = temp;
System.out.println(arr[i]+","+arr[c]);
}
直接插入
我的理解:
数组前面部分是已经排序完成的(第一个元素默认已经排好序,从第二个开始),数组后面部分是需要插入到前面已经排序完成的部分。
从数组后面部分取元素,每次对比移动前面元素的位置,最后空白的位置即插入的位置。是先找到位置然后放进去。
代码实现:
public static void insertSort(int[] arr){
for (int i = 1; i < arr.length; i++) {//第一个元素默认排好序,从第二个开始
int insertFlag = i;//待插入的位置默认i即已经是排序好的数组的最大元素
int insertNum = arr[i];//带插入数字
for (int j = i; j > 0; j--) {//相当于已经排好序的数组部分
if (insertNum < arr[j-1]) {
arr[j] = arr[j-1];//移动
insertFlag = j-1;//标记待插入位置
}
}
arr[insertFlag] = insertNum;
}
}
希尔排序
我的理解:
计算出跨度,跨度左端边界的数字作为一个插入排序的数组。第一轮跨度为数组长度的一半,第二轮排序跨度在为第一轮的一半。
代码实现:
private static void shellSort(int[] arr) {
//i 为跨度
for (int i = (int) Math.floor(arr.length/2); i > 0 ; i=(int) Math.floor(i/2)) {
for (int j = i; j < arr.length; j++) {//[3, 6, 8, 4, 5, 3, 9, 4, 0, 1, 78]
int cur = arr[j];//待排序的值
int flag = j;//默认位置是当前位置
while (flag-i>=0 && cur < arr[flag-i]) {
arr[flag] = arr[flag-i] ;//后移跨度位
flag = flag-i;
}
arr[flag] = cur;
}
}
}
计数排序
我的理解:
1.求得最大值和最小值之差,作为辅助数组长度,初始化辅助数组。
2.将原数组的元素的个数放入辅助数组。
3.辅助数组取值依次赋值给原数组。
代码实现:
public static void countSort(int arr[]){
//获取取最大最小值
int max=0,min=0;
for (int i : arr) {
if (i>max) {
max= i;
}
if (i<min) {
min = i;
}
}
int k = max - min +1;//设置辅助数组长度
int[] c = new int[k];
for (int i : arr) {
c[i-min]++;//将数值依次放入辅助数组,为了减少数组长度下标统一减去 最小值
}
System.out.println("max:"+max+"min:"+min);
//赋值给arr
int kv = 0;//归位下标
for (int i = 0; i < c.length; i++) {
while (c[i]>0) {
arr[kv]=i+min;
kv++;
c[i]--;
}
}
}
基数排序
我的理解:
先求得最大数字的位数,将所有元素从按照个位数分组,然后收回数组,在按照十位分组,收回数组,直到最高位分组,收回数组,完成。负数需要经过特殊处理。
代码实现:
public static void radixSort(int[] arr){
//取最大值
int i=0;
int max = arr[i];
while (i<arr.length) {
if(max < arr[i]){
max = arr[i];
}
i++;
}
int num = 0;//位数
while (max > 1) {
max = max/10;
num++;
}
System.out.println("max:"+max);
System.out.println("num:"+num);
//第一轮 从低位开始排序
int tailNum = 0;//个十百位的数字
int j=0;
int n = 0;
while(j<num){
n = (int) Math.pow(10, j);
//辅助数组
int[][] carr = new int[10][arr.length];//存具体数值
int[] sum = new int[10];//存个数
for (int an = 0; an < arr.length; an++) {
tailNum = (arr[an]/n)%10;//求得某一位上的数字
//入数组
sum[tailNum]++;//一共有几个符合要求的数字
carr[tailNum][sum[tailNum]-1] = arr[an];//存入辅助数组中
}
//将数组赋值给原数组
int k = 0;//arr 增加指针
for (int j2 = 0; j2 < carr.length; j2++) {
if(sum[j2]>0){
for(int l=0;l<sum[j2];l++){
arr[k]=carr[j2][l];
k++;
}
}
}
j++;
}
}