这个的话没什么好说的 就是手撕排序算法.这里买一送一,先手撕一个快排.
//快排
public static void QuickSort(int[] nums){
if (nums.length<=0) return;
QuickSort(nums,0,nums.length-1);
}
public static void QuickSort(int[] nums,int left,int right){
if (left>=right) return;
int random = (int) Math.random()*(right-left+1);
swap(nums,left+random,right);
int[] func = func(nums,left,right);
QuickSort(nums,left,func[0]);
QuickSort(nums,func[1],right);
}
public static int[] func(int[] nums,int left,int right){
int low = left-1;
int high = right;
while (left<high){
if (nums[left]<nums[right]){
swap(nums,++low,left++);
}else if (nums[left]>nums[right]){
swap(nums,--high,left);
}else{
left++;
}
}
swap(nums,high,right);
return new int[]{low,high+1};
}
public static void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
*堆排序正式开始:首先堆排序中的几个重要概念:
- (因为是前序遍历)在数组中i位置的左孩子是(2^i)+1 右孩子是(2^i)+2
- 任意位置index的父节点是(index-1)/2
- 堆排序最重要的两个过程,一个是向上走,一个是想下走.分别对应于heapInsert()和heapify()
具体看代码:
//堆排序 在数组中i位置的左孩子是(2^i)+1 右孩子是(2^i)+2 (因为是前序遍历)
//因此任意位置index的父节点是(index-1)/2
public static void heapSort(int[] arr) {
if (arr==null || arr.length<2) return;
//先得到一个大顶堆
for (int i=0;i<arr.length;i++){
heapInsert(arr,i);
}
//在得到大根堆后 对顶元素就是最大值 将它交换到尾部去
int size = arr.length;
swap(arr,0,--size);//将大顶堆最大位置和最后一个位置做交换 然后size--
while (size>0){
//将剩下的元素进行调整 继续维持大根堆
heapify(arr,0,size);
//在得到大根堆后 对顶元素就是最大值 将它交换到尾部去
swap(arr,0,--size);
}
}
//某个数现在处于index位置,往上继续移动 (往上走)
public static void heapInsert(int[] arr,int index){
//和自己的父节点作比较 只要大于父节点就做交换
while (arr[index]>arr[(index-1)/2]){
swap(arr,index,(index-1)/2);
index = (index-1)/2;
}
}
//将新的节点调整为大顶堆 某个数现在index位置,能否往下移动 (往下走)
public static void heapify(int[] arr,int index,int heapsize){
int left = index*2+1;//左孩子的下标
while(left<heapsize){
//找到左右孩子中的最大值 left+1就是右孩子
int largest = (left+1<heapsize) && arr[left]<arr[left+1] ? left+1:left;
/*
注意!!!!如果写成largest = (left+1<heapsize) && arr[left]>arr[left+1] ? left:left+1;就会出错
arr[left]>arr[left+1] ? left:left+1这一段的逻辑是没有问题的.但是前面还有一个右节点判断的问题(left+1<heapsize) 这里不能忽略
如果右节点判断有问题就会直接返回left+1 然而这个逻辑是有问题的 left+1不符合条件 就不能返回了
所以上面原代码的(left+1<heapsize) && arr[left]<arr[left+1] ? left+1:left;很牛逼
* */
//父和最大的孩子之间,谁的值大,就把下标给largest
largest = arr[largest]>arr[index]? largest:index;
if (largest==index){
break;
}
swap(arr,largest,index);//较大的孩子和父做交换
index = largest;
left = index*2+1;//左孩子的下标
}
}