排序算法

一、冒泡排序
1、原理:将较大元素向后调

 (1)从前往后依次比较相邻的元素,若前者大于后者,则交换两者位置。
 (2)最后一对元素比较完成,则一趟排序结束,最后元素为本趟最大的数。
 (3)每趟除去最后一个元素,从(1)进行下一趟排序,直到只剩下一个元素或某趟排序后标志位没有改变为止。

2、性质:

 (1)稳定性:两个元素相等时,不交换两者位置,则冒泡排序是一种稳定排序算法。
 (2)时间复杂度:
     最好时间复杂度:O(n)
     最坏时间复杂度:O(n^2)
     平均时间复杂度:O(n^2)
 (3)空间复杂度:O(1)

3、Java实现:
import java.util.Arrays;
public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = {4, 3, 2, 1};
        bubbleSort(arr);
        System.out.println(Arrays.toString(arr));
    }
	/**
     * 冒泡排序
     * @param arr 待排序数组
     */
	public static void bubbleSort(int[] arr) {
	  //设置排序趟数
	  for (int i = 0; i < arr.length - 1; i++) {
	      //定义元素交换标志
	      boolean flag = true;
	      //每趟排序,除去最后一个元素
	      for (int j = 0; j < arr.length - 1 - i; j++) {
	          if (arr[j] > arr[j + 1]) {
	              swap(arr, j, j + 1);
	              flag = false;
	          }
	      }
	      //一趟排序结束后,若标志位没有改变,说明冒泡排序完成
	      if (flag) {
	          break;
	      }
	  }
	}
	/**
     * 交换数组元素位置
     * @param arr 目标数组
     * @param i 元素索引
     * @param j 元素索引
     */
	public static void swap(int[] arr, int i, int j) {
	  int temp = arr[i];
	  arr[i] = arr[j];
	  arr[j] = temp;
	}
}
二、快速排序
1、原理:

 (1)定义第一个元素为基准,从左向右定位比基准元素大的值的索引(左索引),从右向左定位比基准元素小的值的索引(右索引),交换两者位置,直到左索引不小于右索引为止。
 (2)交换基准元素与右索引对应的元素,此时左边元素小于或等于基准值,右边元素大于基准值。
 (3)重复(1)、(2),递归左边数组,递归右边数组(递归终止条件:数组左索引大于或等于右索引)。

2、性质:

 (1)稳定性:左边某个元素可能与基准元素相等,交换基准元素与右索引对应的元素后,左边某个元素与基准元素相对位置会发生变化,则快速排序是一种不稳定排序算法。
 (2)时间复杂度:
     最好时间复杂度:O(nlog(n))
     最坏时间复杂度:O(n^2)
     平均时间复杂度:O(nlog(n))
 (3)空间复杂度:O(1)

3、Java实现:
import java.util.Arrays;
public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {4, 2, 6, 8, 7, 2, 9};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }
    /**
     * 递归方式实现快速排序
     * @param arr 待排序的数组
     * @param start 起始索引
     * @param end 终止索引
     */
    public static void quickSort(int[] arr, int start, int end) {
        if (start < end) {
            //保存基准值
            int base = arr[start];
            //定义左索引
            int left = start;
            //定义右索引
            int right = end + 1;
            while (true) {
                //从左向右定位比基准元素大的值的索引
                while (left < end && arr[++left] <= base) ;
                //从右向左定位比基准元素小的值的索引
                while (right > start && arr[--right] >= base) ;
                if (left < right) {
                    //交换两者位置
                    swap(arr, left, right);
                } else {
                    break;
                }
            }
            //交换基准元素与右索引对应的元素,使左边元素都小于或等于基准值,右边元素都大于基准值
            swap(arr, start, right);
            //递归左边数组
            quickSort(arr, start, right - 1);
            //递归右边数组
            quickSort(arr, right + 1, end);
        }
    }
    /**
     * 交换数组元素位置
     * @param arr 目标数组
     * @param i 元素索引
     * @param j 元素索引
     */
    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
三、堆排序
1、原理:

 (1)根据末尾元素,找到末尾元素的父节点,从后向前遍历,找出其左右节点较大的值,若较大子节点大于其父节点值,交换两者位置。
 (2)从末尾元素的父节点开始,由后向前遍历,重复(1),直到头元素为止。
 (3)建立一次大顶堆后,将数组头元素与末尾元素交换,重复(1)、(2)。

2、性质:

 (1)稳定性:建立大顶堆的过程中,两个大小相等的元素相对位置可能会发生变化,则堆排序是一种不稳定排序算法。
 (2)时间复杂度:
     最好时间复杂度:O(nlog(n))
     最坏时间复杂度:O(nlog(n))
     平均时间复杂度:O(nlog(n))
 (3)空间复杂度:O(1)

3、Java实现:
import java.util.Arrays;
public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {1, 4, 7, 2, 5, 8, 6};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    /**
     * 堆排序
     * @param arr 待排序数组
     */
    public static void heapSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            //建立一次大顶堆,数组首个元素最大
            buildMaxBuild(arr, arr.length - 1 - i);
            //每次将首元素交换到数组末尾
            swap(arr, 0, arr.length - 1 -i);
        }
    }
    /**
     * 建立大顶堆:建一次大顶堆,数组首个元素最大
     * @param arr 待排序数组
     * @param lastIndex 末尾索引
     */
    public static void buildMaxBuild(int[] arr, int lastIndex) {
        //根据末尾元素,找到末尾元素的父节点,进行从后往前遍历
        for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
            int currentIndex = i;
            //判断当前索引是否存在子节点
            while (2 * currentIndex + 1 <= lastIndex) {
                //存在子节点,定义左子节点为较大值对应的索引
                int biggerIndex = 2 * currentIndex + 1;
                //判断是否存在右子节点
                if (biggerIndex < lastIndex) {
                    //比较左右子节点大小,找到较大值索引
                    if (arr[biggerIndex + 1] > arr[biggerIndex]) {
                        biggerIndex++;
                    }
                }
                //比较子节点与父节点的值
                if (arr[biggerIndex] > arr[currentIndex]) {
                    //子节点大于父节点值,交换对应位置
                    swap(arr, biggerIndex, currentIndex);
                    //交换位置后,较大索引处的值发生变化,再次循环,判断是否存在子节点
                    currentIndex = biggerIndex;
                } else {
                    //没有交换,直接结束本次循环
                    break;
                }
            }
        }
    }
    /**
     * 交换数组元素位置
     * @param arr 目标数组
     * @param i 元素索引
     * @param j 元素索引
     */
    public static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
四、归并排序
1、原理:

 (1)申请空间,使其大小为两个已经排好序的数组长度之和,该空间用来存放合并后的数组。
 (2)定义两个指针,最初位置分别为两个已经排好序数组的起始位置。
 (3)比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置,重复(3),直到其中一个指针超出数组。
 (4)将另一数组剩下的所有元素直接复制到合并数组的尾部

2、性质:

 (1)稳定性:数组元素合并时,若两数相等,相对位置较前者先放到辅助数组中,则归并排序是一种稳定排序算法。
 (2)时间复杂度:
     最好时间复杂度:O(nlog(n))
     最坏时间复杂度:O(nlog(n))
     平均时间复杂度:O(nlog(n))
 (3)空间复杂度:O(n)

3、Java实现:
import java.util.Arrays;
public class MergeSort {
    public static void main(String[] args) {
        int[] arr = {4, 5, -1, 2, 8, 6};
        mergeSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }
    /**
     * 使用递归方式实现归并排序
     * @param arr 待排序数组
     * @param left 起始索引
     * @param right 终止索引
     */
    public static void mergeSort(int[] arr, int left, int right) {
        //递归遍历到只有两个元素
        if (left < right) {
            //定义数组中间索引
            int center = (left + right) / 2;
            //递归左数组
            mergeSort(arr, left, center);
            //递归右数组
            mergeSort(arr, center + 1, right);
            //左右数组元素合并
            merge(arr, left, center, right);
        }
    }
    /**
     * 数组元素比较合并
     * @param arr 待合并数组
     * @param left 起始索引
     * @param center 中间索引
     * @param right 终止索引
     */
    public static void merge(int[] arr, int left, int center, int right) {
        //开辟临时数组
        int[] tempArr = new int[arr.length];
        //定义临时数组索引
        int tempIndex = left;
        //定义右数组起始索引
        int middle = center + 1;
        //定义起始索引
        int tempLeft = left;
        //左右两个数组元素比较大小,较小者保存到临时数组
        while (left <= center && middle <= right) {
            if (arr[left] <= arr[middle]) {
                tempArr[tempIndex++] = arr[left++];
            } else {
                tempArr[tempIndex++] = arr[middle++];
            }
        }
        //左数组有剩余
        while (left <= center) {
            tempArr[tempIndex++] = arr[left++];
        }
        //右数组有剩余
        while (middle <= right) {
            tempArr[tempIndex++] = arr[middle++];
        }
        //将排好序的临时数组复制到原数组
        while (tempLeft <= right) {
            arr[tempLeft] = tempArr[tempLeft++];
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值