1.冒泡排序
基本思想:从前向后(从下标较小的元素开始)依次比较相邻元素的值,若发现逆序则交换,使值相对较大的元素逐渐从前移动到后部。
优化:
在排序的过程中,各元素不断接近自己的位置,如果一趟下来没有进行过交换,就说明序列有序,因此在排序过程中设置一个标志flag判断元素是否被交换过,从而减少不必要的比较。
class Solution {
public int[] sortArray(int[] nums) {
Boolean isFlag = true;
int i,j,temp;
for(i = 1;i < nums.length && isFlag;i++){
isFlag = false;
for(j = nums.length - 1;j >= i;j--){
if(nums[j - 1] > nums[j]){
temp = nums[j];
nums[j] = nums[j - 1];
nums[j - 1] = temp;
isFlag = true;
}
}
}
return nums;
}
}
2.插入排序
基本思想:把n个待排序的元素看成一个有序表和一个无序表。开始时有序表中只包含一个元素,无序表中包含n-1个元素。排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将其插入到适当位置。
class Solution {
public int[] sortArray(int[] nums) {
int inVal,index;
for(int i = 1;i < nums.length;i++){
inVal = nums[i];//待插入的值
index = i - 1;//待插入的前一个
while(index >= 0 && inVal < nums[index]){//一直向前寻找比当前待插入值小的之后插入,然后将待插入的位置的值依次赋值给后一个
nums[index + 1] = nums[index];
index--;//往前找
}
if(index + 1 != i){//如果不是插在当前位置
nums[index + 1] = inVal;//就将待插入的值赋给插入的位置
}
}
return nums;
}
}
3.选择排序
基本思想:第一个从arr[0] - arr[n-1]中选取最小值,和arr[0]交换;第二次从arr[1]-arr[n-1]中选取最小值,与arr[1]交换;第三次从arr[2]-arr[n-1]中选取最小值,与arr[2]交换;······一直到第n-1此从arr[n-2]-arr[n-1]中选取最小值,与arr[n-2]交换,。得到一个按排序吗从小到大排列的有序序列
class Solution {
public int[] sortArray(int[] nums) {
int min,index;
for(int i = 0;i < nums.length;i++){
min = nums[i];
index = i;
for(int j = i + 1;j < nums.length;j++){
if(min > nums[j]){
min = nums[j];
index = j;
}
}
if(index != i){//如果最小值不是当前值再交换
nums[index] = nums[i];
nums[i] = min;
}
}
return nums;
}
}
4.希尔排序
设置初始增量gap = arr.length / 2;对其分别进行直接插入排序,然后缩小增量gap = gap/2继续进行直接插入排序········
class Solution {
public int[] sortArray(int[] arr) {
for(int gap = arr.length / 2; gap > 0;gap /= 2){
for(int i = gap;i < arr.length;i++){
int j = i;
int temp = arr[j];
if(arr[j] < arr[j - gap]){
while(j - gap >= 0 && temp < arr[j - gap]){
arr[j] = arr[j - gap];
j -= gap;
}
arr[j] = temp;
}
}
}
return arr;
}
}
5.快速排序
对冒泡排序的一种改进,基本思想就是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分所有数据都比另外一部分所有数据都要小,然后再按此方法对这两部分分别进行快速排序,整个排序过程递归进行。
1)数组的快排
//数组的快排
class Solution {
public int[] sortArray(int[] arr) {
quickSort(arr,0,arr.length - 1);
return arr;
}
public void quickSort(int[] arr,int left,int right){
int l = left;//左下标
int r = right;//右下标
int mid = arr[(left +right) / 2];//中轴值
int temp = 0;
//while循环比mid大的放右边,小的放左边
while(l < r){
//左边一直找,找到比mid大的就退出
while(arr[l] < mid) l++;
//右边一直找,找到比mid小的就退出
while(arr[r] > mid) r--;
if(l >= r) break;//全部找完,左边全小于mid,右边全大于mid
//交换arr[l] arr[r]
temp= arr[l];
arr[l] = arr[r];
arr[r] = temp;
if(arr[l] == mid) r--;
if(arr[r] == mid) l++;//防止数组越界
}
if(l == r) {l++; r--;}//
if(left < r) quickSort(arr,left,r);//向左递归
if(right > l) quickSort(arr,l,right); //向右递归
}
}
2)链表的快排
//迭代法
public ListNode sortList(ListNode head) {
if(head == null) return null;
//快速排序
ListNode curr = new ListNode(0,head);
ListNode slow = head;
ListNode fast = head.next;
ListNode tmp = null;
while(fast != null){
if(slow.val <= fast.val){//待排节点值大于已排序好的末尾的节点值,
tmp = fast.next;
slow = fast;//就直接放到末尾节点的后面,
fast = tmp;//然后向后移动继续遍历
continue;
}//否则:待排的节点值小于不已经排好的末尾节点值
ListNode pre = curr;//排好的首端
ListNode nxt = curr.next;//用于保存待插入的下一个节点值
ListNode nxfast = fast.next;//保存未排序的节点
while(nxt != fast){//遍历到第一个未排序的节点之前
if(fast.val < nxt.val){//如果找到了插入的位置
slow.next = fast.next;//先将已排序的末端和待排序的首端连接好
fast.next = nxt;//将待排序的节点插入
pre.next = fast;
break;
}//没找着就接着遍历往后找
pre = nxt;
nxt = nxt.next;
}
fast = nxfast;//最后把fast跳到未排序的首端,继续下一次遍历
}
return curr.next;
}
//递归法------力扣超时
class Solution {
public ListNode sortList(ListNode head) {
//快排2
if(head == null || head.next == null) return head;
ListNode dummy = new ListNode(-1);
dummy.next = head;
return quickSort(dummy,null);
}
private ListNode quickSort(ListNode head,ListNode end){
if(head == end || head.next == end || head.next.next == end) return head;
ListNode tmphead = new ListNode(-1);//临时链表
ListNode mid = head.next;//分割点
ListNode right = mid;//待排链表指针
ListNode left = tmphead;//临时链表指针
while(right.next != end){//将小于划分点的值存储在临时链表中
if(right.next.val < mid.val){
left.next = right.next;
left = left.next;
right.next = right.next.next;
}else{
right = right.next;
}
}
left.next = head.next;//合并临时链表和原链表
head.next = tmphead.next;//将临时链表插回源链表
quickSort(head,mid);//向左递归
quickSort(mid,end);//向右递归
return head.next;
}
}
6.归并排序
1)数组的归并
class Solution {
public int[] sortArray(int[] arr) {
int[] temp = new int[arr.length];
if(arr.length == 0) return new int[0];
mergeSort(arr,0,arr.length - 1,temp);
return arr;
}
//分——合
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,mid,right,temp);//合并
}
}
//合
public void merge(int[] arr,int left,int mid,int right,int[] temp){
int i = left; //左边序列的初始索引
int j = mid + 1; //右边序列的初始索引
int t = 0;//temp的当前索引
//将左右两边的有序数据按顺序填充到temp,直到有一边处理完毕为止
while(i <= mid && j <= right){
if(arr[i] <= arr[j]){
temp[t] = arr[i];
t++;
i++;
}else{
temp[t] = arr[j];
t++;
j++;
}
}
//将剩余一侧的数据继续填充
while(i <= mid){
temp[t] = arr[i];
t++;
i++;
}
while(j <= right){
temp[t] = arr[j];
t++;
j++;
}
//将temp数组拷贝到arr,并不是拷贝所有
t = 0;
int tempLeft = left;
while(tempLeft <= right){
arr[tempLeft] = temp[t];
t++;
tempLeft++;
}
}
}
2)链表的归并
class Solution {
public ListNode sortList(ListNode head) {
return head == null ? null : mergeSort(head);
}
//归并排序-----“分”
public ListNode mergeSort(ListNode head){
if(head == null || head.next == null) return head;//没有节点或者只有一个节点
//1.快慢指针找中间节点
ListNode slow = head,fast = head.next;
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
ListNode left,right;
right = mergeSort(slow.next);//对右边部分进行归并排序
slow.next = null;//左边部分的结束标志,末尾节点.next==null
left = mergeSort(head);//对左半部分进行归并排序
return mergeList(left,right);//合并左右两部分链表返回
}
//合并两个有序链表-----“治”
ListNode mergeList(ListNode l,ListNode r){
ListNode dummy = new ListNode(-1);
ListNode tmp = dummy;
while(l != null && r != null){
if(l.val < r.val){
tmp.next = l;
l = l.next;
}else{
tmp.next = r;
r = r.next;
}
tmp = tmp.next;
}
tmp.next = l == null ? r : l;
return dummy.next;
}
}
7.桶排序
class Solution {
public int[] sortArray(int[] arr) {
if(arr.length == 0) return new int[0];
int max = Integer.MIN_VALUE;
for(int i = 1;i < arr.length;i++){
if(Math.abs(arr[i]) > max){
max = arr[i];
}
}
if(max < 0) max = -max;
int maxLength = (max + "").length();//最大数的位数
int[][] bucket = new int[19][arr.length];//定义桶
int[] bucketElementCount = new int[19];//记录每个桶中存放多少个数据
for(int i = 0,n = 1;i < maxLength;i++,n*=10){//对每一位进行排序
for(int j = 0;j < arr.length;j++){
int arri = arr[j] / n % 10;//取出每个元素对应位的值放入桶中
bucket[arri + 9][bucketElementCount[arri + 9]++] = arr[j];
}
int index = 0;
//按照桶的顺序,遍历放入到原来的数组中
for(int k = 0;k < 19;k++){
if(bucketElementCount[k]!=0){//桶中有数据才放到原数据
for(int l = 0;l < bucketElementCount[k];l++){
arr[index++] = bucket[k][l];
}
}
bucketElementCount[k] = 0; //将每个计数的清零
}
index = 0;
}
return arr;
}
}
8.堆排序
堆:具有以下性质的完全二叉树:
大顶堆:每个节点的值都大于或者等于左右孩子节点的值
小顶堆:每个节点的值都小于等于其左右孩子节点的值
思想
升序采用大顶堆,降序采用小顶堆
以升序为例
1)将待排序序列构造成一个大顶堆,此时最大值就是堆顶的根节点
2)将堆顶元素和末尾元素交换,此时末尾元素就是最大值
3)然后将剩余n-1个元素重新构造一个堆,得到n个元素的次小值,反复执行,就得到一个有序序列了。
public void heapSort(int[] arr){
int tmp = 0;
//构建大顶堆或者小顶堆
for(int i = arr.length / 2 - 1;i >= 0;i--){
adjustHeap(arr,i,arr.length);
}
//将堆顶元素和末尾元素交换,将最大元素“沉”到数组末端
for(int j = arr.length - 1;j > 0){
tmp = arr[j];
arr[j] = arr[0];
arr[0] = tmp;
adjustHeap(arr,0,j);
}
}
//将数组调整成大顶堆
void adjustHeap(int[] arr,int i,int length){
int tmp = arr[i];
for(int k = i * 2 + 1;k < length;k=k * 2 + 1){
if(k + 1 < length && arr[k] < arr[k + 1]) k++;左子节点的值小于右子节点的值,指向右子节点
if(arr[k] > tmp){//子节点大于父结点
arr[i] = arr[k];//将较大的值赋给当前结点
i = k;//指向k,继续进行循环比较
}else{
break;
}
}
arr[i] = tmp;//for循环结束,我们已将以i为父结点的树的最大值放在了最顶端(局部的)
}
9.基数排序
/*
堆排序的思想借助于二叉堆中的最大堆得以实现。首先,将待排序数列抽象为二叉树,并构造出最大堆;
然后,依次将最大元素(即根节点元素)与待排序数列的最后一个元素交换(即二叉树最深层最右边的叶子结点元素);
每次遍历,刷新最后一个元素的位置(自减1),直至其与首元素相交,即完成排序。
*/
class Solution {
public int[] sortArray(int[] arr) {
int size = arr.length;
for(int i = size/ 2 -1;i >= 0;i--){
adjust(arr,size,i);
}
for(int i = size - 1;i >= 1;i--){
int temp = arr[0];
arr[0] = arr[i];
arr[i] = temp;
adjust(arr,i,0);
}
return arr;
}
public void adjust(int[] nums,int len,int index){
int l = 2 * index + 1;
int r = 2 * index + 2;
int maxIndex = index;
if (l<len&&nums[l]>nums[maxIndex])maxIndex = l;
if (r<len&&nums[r]>nums[maxIndex])maxIndex = r;
if (maxIndex != index) {
int temp = nums[maxIndex];
nums[maxIndex] = nums[index];
nums[index] = temp;
adjust(nums, len, maxIndex);
}
}
}