// 直接插入排序
public static void insertSort(int[] nums){
/*
* 思想:将一个元素插入一个已经排过序的数组
*实例:假设数组的第二个元素为要插入的元素,第一个元素为已经排过序的数组
* */
// 依次遍历插入
for(int i=1;i<nums.length;i++){
// 说明需要插入(这里和已排序数组的最大值进行比较,小于最大值,说明需要插入)
if(nums[i] < nums[i-1]){
int temp = nums[i];
// 确定要插入的位置(先记录索引,不要见一个就交换一个)
int j ;
for( j=i-1;j>=0&& nums[j]>temp;j--){
// 依次往后移动
nums[j+1] = nums[j];
}
// 此时nums[j] <=temp, 将temp交换至+1处
nums[j+1] = temp;
}
}
}
// 希尔排序
public static void shellSort(int[] nums){
/*
*思想:先局部有序,再总体有序
* 具体思路:
* 1.通过一个增量(如nums.length/2),来进行分组,(0->d)的元素的倍数为一组
* 2. 分组后,通过通过直接插入排序进行排序
* */
// 确定初始增量
int d = nums.length/2;
// 通过whle 不断改变增量
while (true){
// 循环结束条件
if(d == 1){
break;
}
// 增量递减
d=d/2;
// 确定每组的初始值,遍历每组
for(int x = 0;x<d;x++){
// ---------采用直接插入排序进行排序------------
for(int i= x+d;i<nums.length;i=i+d){ // 每组的第二个元素开始,因为直接插入排序的思想
// 确定可以去插入
if(nums[i]<nums[i-d]){
int temp = nums[i];
// 将位置向右移
int j;
for(j = i-d;j>=0 && nums[j]>temp;j=j-d){
nums[j+d] = nums[j]; // 需要把nums[i] 站住
}
// 经过循环后,nums[j]<=temp,故调换的位置在nums[j+d]
nums[j+d] = temp;
}
}
}
}
}
//冒泡排序
public static void bubbleSort(int[] nums){
/*
* 思想:依次比较相邻的两个元素,一轮下来会产生一个最大(或最小的元素)
*
* */
for(int i=0;i<nums.length-1;i++){ // n-1轮
for(int j = 0;j<nums.length-1-i;j++) // -i是因为i轮后,会有i个元素的有序数组在后面
{
if(nums[j] >nums[j+1]){
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
}
}
}
}
//快速排序
/**
*
* @param nums 排序的数组
* @param left 数组的初始位置
* @param right 数组的末尾位置
*/
public static void quickSort(int[] nums,int left,int right){
/*
* 思想:
* 1.以第一个元素为基准(其他数也行)
* 2. 首先从右侧指针开始,定位到一个比基准数小的元素的位置
* 3.然后从左侧开始,定位到一个比基准数大的元素的位置
* 4.交换这两个位置
* 5.然后继续移动,直到左右指针相等,这时,left == right
* 6.交换基准数宇nums[left]or nums[right]的位置
* 7.这时以left or right 位置为中心,分成两个数组,依次使用 递归 ,快排 排序
* */
// 递归结束条件
if(left>right){
return;
}
// 首先记录 left 与right的位置
int begin = left ;
int end = right;
// 基准数
int baseNum = nums[left];
// 移动左右指针,交换位置 ,最后交换基准数
while (begin<end){
// 移动右侧指针,定位到比baseNum 小的元素的位置
while (nums[end] >=baseNum && begin<end){
end--;
}
//移动左侧指针,定位到比baseNum大的元素的位置
while (nums[begin]<=baseNum && begin<end){
begin++;
}
// 满足交换条件
if(begin<end){
int temp = nums[begin];
nums[begin] = nums[end];
nums[end] = temp;
}
}
// 交换基准数与nums[begin or end]位置
int tmp =nums[left];
nums[left] =nums[end];
nums[end] = tmp;
// 左侧子数组递归,快排
quickSort(nums,left,end-1);
// 右侧子数组递归,快排
quickSort(nums,end+1,right);
}
// 直接选择排序、
public static void selectSort(int[] nums){
/*
* 思想:就是我们最常用的排序思想,选择一个元素与生于的所有元素进行比较
* */
for(int i = 0;i<nums.length-1;i++){
// 记录最小值的索引位置,这样就不用每交换一次
int minIdx = i;
for(int j =i+1;j<nums.length;j++){
// 小的放前面
if(nums[j]<nums[minIdx]){
minIdx = j;
}
}
swap(nums,minIdx,i);
}
}
// 堆排序
public static void heapSort(int[] nums){
/*
* 思想: 参考:https://blog.youkuaiyun.com/u013384984/article/details/79496052
* 1.构建大顶堆(len/2 个非叶子节点开始,依次递减调整,直至到0
* 2.交换堆顶和堆尾元素
* 3.除交换的堆尾元素外,将剩余元素重新调整为大顶堆
* */
int len = nums.length;
// 初始化堆
for(int x = len/2;x>=0;x--){
heapAdjust(nums,x,len);
}
// 交换元素,重新调整len-1个数组的堆
for (int i = nums.length-1;i>=0;i--){
// 交换元素
swap(nums,0,i);
len--;
// 重新调整 剩下元素为大顶推
heapAdjust(nums,0,len);
}
}
// 调整堆
public static void heapAdjust(int[] nums,int i,int len){
/*
* 思想:调整时,只沿着改变的那个子节点的方向,进行向下调整
* 原因:因为两个没改变的节点的方向,是最大堆了,不需要再调整了
* */
// 左右子节点
int leftNo = 2*i+1;
int rightNo = 2*i+2;
// 先构建这三个节点的最大堆
// 默认当前父节点,在这三个节点中,值为最大的那个
int largest = i;
// 左子节点与父节点先比较
if(leftNo<len &&nums[largest] < nums[leftNo]){
largest = leftNo;
}
// 再右节点与largest 节点比较
if(rightNo<len && nums[largest] < nums[rightNo]){
largest =rightNo;
}
// 如果改变了,则交换位置
if(largest != i){
swap(nums,i,largest);
// 递归往深层调整(也可采用循环的方式(k,k+1),我才用的是递归的方式)
heapAdjust(nums,largest,len);
}
}
// 归并排序
/**
*
* @param nums
* @param low 数组首位
* @param high 数组末位
*/
public static void mergeSort(int[] nums,int low,int high){
/*
* 思想:通过递归的方法把数组分为两个有序数列,然后合并,
* 递归前进时进行划分,退回时进行合并
*
* 当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序
* */
if(low<high){
// 数组分割成两个左右数组
int mid = (low+high)/2; // 这里时low+high 不是high-low
// 左子序递归排序
mergeSort(nums,low,mid);
// 右子序递归排序
mergeSort(nums,mid+1,high);
// 合并两个有序数组
merge(nums,low,mid+1,high);
}
}
// 合并两个有序数组
public static void merge(int[] nums,int low,int mid,int high){
int i = low;
int j = mid;
// 创建一个临时数组(需要第三个数组)
int[] tempArray = new int[high-low+1];
int k= 0;
while (i<mid && j<=high){
if(nums[i]>nums[j]){
// 先放入临时数组
tempArray[k++] = nums[j++]; // 放入小的
}else {
tempArray[k++] = nums[i++];
}
}
// 如果有数组没有放完
while (i<mid){
tempArray[k++] =nums[i++];
}
while (j<=high){
tempArray[k++] = nums[j++];
}
// 将tempArray copy到nums low 至 high 处
for(int m = 0;m<k;m++){
nums[low++] = tempArray[m];
}
}
// 基数排序
/**
*
* @param nums
* @param d 数组最大元素的位数
*/
public static void radixSort(int[] nums,int d){
/*
* 思想:
* 1.依次将数组元素的个位数至最高位数,放到标号0-9的桶子里,每一轮要将
* 放好的元素,重新串起来,再开始下一轮位数的放置
*
* */
// 依次遍历各位,放置后,重新串起来开启下一轮
int m = 1; // 记录循环到哪一位了(如十位、百位)
int n =1; // 用于控制获取哪一位的数
while (m<d){
// 创建桶子
int[][] barrel = new int[10][nums.length];
// 创建 记录每个桶子所含元素的计数器
int[] counter = new int[10];
// 开始依据位数元素,放置梗
// 记录每个序号里桶子里元素的个数
int[] cur_num = new int[10];
for(int i=0;i<nums.length;i++){
// 获取当前位上的 数
int single_num = (nums[i]/n)%10;
// 放入带有序号的桶子(对于位数相等的,因为上一位已经排序了,故相同号的桶,
// 小的数是放在数组左边的,故下面串起来时,就直接是从小到大的
barrel[single_num][cur_num[single_num]] = nums[i]; // 这里理解一下
cur_num[single_num]++;
}
// 把元素串一起
int idx =0;
for(int p=0;p<10;p++){
if(cur_num[p]>0){
for(int q=0;q<cur_num[p];q++){
nums[idx++] = barrel[p][q];//
}
}
}
// 开启下一轮
m++;
n=n*10;
}
}
// 比较工具
/**
*
* @param nums 数组
* @param i 索引i
* @param j 索引j
*/
public static void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}