/*
* 排序算法:
* 交换排序:快速排序(O(NlogN),不稳定)、冒泡排序(O(N^2),稳定)
* 插入排序:直接插入排序(O(N^2),稳定)、希尔排序(O(N^1.3)不稳定)
* 选择排序:直接选择排序(O(N^2),不稳定),堆排序(O(NlogN),不稳定)
* 归并排序(O(NlogN),稳定)
*/
public class Sort {
/*
* 1.快速排序,该方法有三个参数,数组arr,需要进行排序的部分数组(由low和high截取),然后找
* 一个基准值(一般为需要排序的数组的第一个元素),确定基准值所在的位置(start=end时),再使用
* 递归对基准值两边的元素继续进行快排。
*
* 简言之,快排第一步就是确定基准值的位置,然后再进行递归求解。
*/
public static void quicklySort(int arr[], int low, int high) {
int key = arr[low];
int start = low;
int end = high;
while (start < end){
while (arr[end] >= key && start < end){
end--;
}
arr[start] = arr[end];
while (arr[start] <= key && start < end){
start++;
}
arr[end] = arr[start];
}
arr[start] = key; // 将基准值填到相应位置
if (start > low)
quicklySort(arr, low, start - 1);
if (end < high)
quicklySort(arr, end + 1, high);
}
/*
* 2.冒泡排序,遇见比当前数小的就交换顺序
*/
public static void bubbleSort(int arr[]) {
int temp;
for (int i = 0; i < arr.length; i++){
for (int j = arr.length - 1; j > i; j--){ //从后往前冒,当然也可以从前往后沉
if (arr[j] < arr[j - 1]){
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
}
}
}
}
/*
* 3.直接插入排序,假设数组第一个元素自成一个有序序列,从第二个元素起,依次与前面的元素进行
* 比较,插入到正确的位置以构成有序序列,直到最后一个元素插入到正确位置从而使得整个数组有序。
*/
public static void insertionSort(int arr[]) {
int temp;
for (int i = 1; i < arr.length; i++){ //i表示从哪个位置的元素开始与它之前的元素进行比较
int j = i;
while (j > 0 && arr[j] < arr[j - 1] ){//这里不用for循环是因为使用for循环则无论arr[j]是否小于arr[j-1],都要进行j--的操作
temp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = temp;
j--;
}
}
}
/*
* 4.希尔排序,改进的直接插入排序,先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行
* 直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入
* 排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有
* 较大提高。步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。
*/
public static void shellSort(int arr[]) {
int increment;
for (increment = arr.length / 2; increment > 0; increment /= 2){
//增量之后进行直接插入排序
for (int j = increment; j < arr.length; j++){
if (arr[j] < arr[j - increment]){
int temp = arr[j];
int k = j - increment;
while (k >= 0 && arr[k] > temp){
arr[k + increment] = arr[k];
k -= increment;
}
arr[k + increment] = temp;
}
}
}
}
/*
* 5.直接选择排序,思想就是从第一个元素开始遍历数组,找到数组中的最小元素跟第一个元素交换
* 位置,然后接着从第二个元素开始重复刚才的过程,直到最后一个元素,跟冒泡不同,直接选择排序
* 是每一次遍历只交换一次元素,而冒泡则是只要发现当前元素比前面的元素小就要交换位置。
*/
public static void selectionSort(int arr[]) {
int min;//记录最小元素的索引位置
int temp;
for (int i = 0; i < arr.length - 1; i++){
min = i;
for (int j = i + 1; j < arr.length; j++){
if (arr[j] < arr[min]){
min = j;
}
}
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
/*
* 6.堆排序,升序构建最大堆(父大于子),
* 首先,构建最大堆buildMaxHeap();需要借助筛选函数heapScreen();
* 其次,将堆顶元素跟堆得最后一个元素交换位置(最大值放后边)
*
*/
//n为构建堆的节点总数
public static void buildMaxHeap(int arr[], int n) {
//1.构建最大堆
for (int i = (n - 1) / 2; i >= 0; i--){//从最后一个非叶子结点开始筛选 i = (n - 1) / 2
heapScreen(arr, i, n);
}
}
//筛选,即调整元素位置,使之满足最大堆的性质,i为开始节点,n为节点总数
public static void heapScreen(int arr[], int i, int n) {
int temp = arr[i];
int j = 2 * i + 1;//左孩子
while (j < n){
if (j + 1 < n && arr[j] < arr[j + 1])
j++;
if (arr[j] <= temp)
break;
arr[i] = arr[j];
i = j;
j = 2 * i + 1;
}
arr[i] = temp;
}
public static void heapSort(int arr[]) {
for (int i = arr.length; i > 0; i-- ){
buildMaxHeap(arr,i);
System.out.println(arr[0]);
//注意:这里交换元素不能用swap函数,这涉及到引用传递的问题。详情见博客
int temp = arr[0];
arr[0] = arr[i - 1];
arr[i - 1] = temp;
}
}
/*7、归并排序
* 步骤:先递归拆分(sort),然后合并(merge),排序在合并中实现
*/
public static void mergeSort(int arr[]){
sort(arr, 0, arr.length - 1);
}
public static void sort(int arr[], int low, int high) {
if (low < high){
int mid = (low + high) / 2;
sort(arr, 0, mid);
sort(arr, mid + 1, high);
merge(arr, low, mid, high);
}
}
public static void merge(int arr[], int low, int mid, int high) {
int i = low;
int j = mid + 1;
int temp[] = new int[arr.length];//定义长度为arr.length的数组是为了下标能跟arr对上
int k = low;//临时数组temp的下标
while (i <= mid && j <= high){
if (arr[i] <= arr[j])
temp[k++] = arr[i++];
else
temp[k++] = arr[j++];
}
while (i <= mid)
temp[k++] = arr[i++];
while (j <= high)
temp[k++] = arr[j++];
for (int n = low; n <= high; n++)
arr[n] = temp[n];
}
}
常见排序算法
最新推荐文章于 2024-11-08 21:44:34 发布