排序
首先假设:①数据是整数 ②存储在数组中 ③ 升序排序
1、插入排序:
先将数组的元素:list[i] 存储在一个名为 flag 的临时变量中,如果list[i-1]>flag,就将list[i-1]移动到list[i]中,果list[i-2]>flag,就将list[i-2]移动到list[i-1]中。依次类推,完成整个排序,时间复杂度是 O(n²)。
public class InsertSort {
public static void main(String[] args) {
int[] list = {2,5,9,4};
for (int i = 1; i < list.length; i++) {//i=1是从5开始进行比较。
int flag=list[i];
int k;
for(k=i-1;k>=0&&list[k]>flag;k--)//
{
list[k+1]=list[k];
}
list[k+1]=flag; //k的值可能是-1
}
System.out.println(Arrays.toString(list));
}
}
2、冒泡排序:
冒泡排序需要遍历好几遍数组,在每次遍历中,比较相邻的两个数据,比如如果list[k]>list[k+1],则将这两个数交换(默认升序排序);在最佳情况下只需要遍历一次,最差情况下时间复杂度为O(n²)。
public class BubbleSort {
public static void bubbleSort(int[] list) {
boolean needNextPass = true;
for (int k = 1; k < list.length && needNextPass; k++) {
// 如果没有发生交换,代表已经排好序,needNextPass为false;则不需要再继续遍历了。
needNextPass = false;
for (int i = 0; i < list.length - k; i++) {
if (list[i] > list[i + 1]) {
// 交换数据
int temp = list[i];
list[i] = list[i + 1];
list[i + 1] = temp;
needNextPass = true; //发生交换了,此时还需要继续编辑数组
}
}
}
}
public static void main(String[] args) {
int[] list = {2, 3, 2, 5, 6, 1, -2, 3, 14, 12};
bubbleSort(list);
for (int i = 0; i < list.length; i++)
System.out.print(list[i] + " ");
}
}
3、归并排序
归并排序算法将数组分为两个部分,对每部分分别递归地应用归并排序。时间复杂度为O(nlogn),优于选择排序、插入排序、冒泡排序。java.util.Arrays中的sort方法就是使用归并排序算法变体而来。
public class MergeSort {
/** The method for sorting the numbers */
public static void mergeSort(int[] list) {
if (list.length > 1) {
// Merge sort the first half
int[] firstHalf = new int[list.length / 2];
/**
* arraycopy参数:
* list – 源数组。
* 0 – 源数组中的起始位置。
* firstHalf – 目标数组。
* 0 – 目标数据中的起始位置。
* list.length / 2 – 要复制的数组元素的数量。
*/
System.arraycopy(list, 0, firstHalf, 0, list.length / 2);
mergeSort(firstHalf);
//每一部分的递归运算完才运算下一部分的递归,所以就算使用相同的目标数组名称也不会发生数据域冲突
// Merge sort the second half
int secondHalfLength = list.length - list.length / 2;
int[] secondHalf = new int[secondHalfLength];
System.arraycopy(list, list.length / 2,
secondHalf, 0, secondHalfLength);
mergeSort(secondHalf);
// Merge firstHalf with secondHalf into list
merge(firstHalf, secondHalf, list);
}
}
/** Merge two sorted lists */
public static void merge(int[] list1, int[] list2, int[] temp) {
int current1 = 0; // Current index in list1
int current2 = 0; // Current index in list2
int current3 = 0; // Current index in temp
while (current1 < list1.length && current2 < list2.length) {
if (list1[current1] < list2[current2])
temp[current3++] = list1[current1++];
else
temp[current3++] = list2[current2++];
}
while (current1 < list1.length)
temp[current3++] = list1[current1++];
while (current2 < list2.length)
temp[current3++] = list2[current2++];
}
/** A test method */
public static void main(String[] args) {
int[] list = {2, 3, 2, 5, 6, 1, -2, 3, 14, 12};
mergeSort(list);
for (int i = 0; i < list.length; i++)
System.out.print(list[i] + " ");
}
}
4、快速排序
在数组中找到一个基准元素,从两端向中间同时遍历数组与基准元素比较,将数组分为左右两部分,然后对两个部分分别递归应用快速排序算法。
快速排序时间复杂度的平均时间是O(nlogn)。
在最差情况下,归并排序的效率会高于快速排序,但是平均情况下两者相同。而归并排序在归并两个子数组时需要创建一个临时数组,快速排序不用。所以快速排序的空间效率高于归并排序。
public class QuickSort {
public static void quickSort(int[] list) {
quickSort(list, 0, list.length - 1);
}
private static void quickSort(int[] list, int first, int last) {
if (last > first) {
int pivotIndex = partition(list, first, last);
quickSort(list, first, pivotIndex - 1);
quickSort(list, pivotIndex + 1, last);
}
}
/** Partition the array list[first..last] */
private static int partition(int[] list, int first, int last) {
int pivot = list[first]; // Choose the first element as the pivot
int low = first + 1; // Index for forward search
int high = last; // Index for backward search
while (high > low) {
// 找到右侧比基准元素小的值的下标
while (low <= high && list[low] <= pivot)
low++;
// 找到左侧比基准元素大的值的下标
while (low <= high && list[high] > pivot)
high--;
// 两个值互相交换,再回到循环开始 直到high<low
if (high > low) {
int temp = list[high];
list[high] = list[low];
list[low] = temp;
}
}
//从右边部分的数据的从左开始找到小于当前基准元素的值
while (high > first && list[high] >= pivot)
high--;
// 将基准元素的值放到数据中间,并返回该下标
if (pivot > list[high]) {
list[first] = list[high];
list[high] = pivot;
return high;
}
else {
return first;
}
}
/** A test method */
public static void main(String[] args) {
int[] list = {2, 3, 2, 5, 6, 1, -2, 3, 14, 12};
quickSort(list);
for (int i = 0; i < list.length; i++)
System.out.print(list[i] + " ");
}
}
5、堆排序
堆排序使用一个二叉堆,该二叉堆是一颗完全二叉树,如果一颗二叉树的每一层都是满的,或者最后一层没填满并且最后一层的叶子都是靠最左放置的。
堆排序的时间复杂度为O(nlogn),与归并排序相同。但堆排序不需要额外的临时数组空间,所以堆排序的空间效率高于归并排序。
二叉堆是一颗具有以下属性的二叉树:
①形状属性:它是一棵完全二叉树
②堆属性:每个节点大于或等于它的任何一个孩子
5.1、堆的存储
5.2、添加一个新的节点
将新的元素放置在堆的最后位置,也就是完全二叉树的末尾下一个节点。然后再与父节点比较大小,交换位置直到满足上述两个关于二叉堆的条件。
5.3、删除根结点
经常需要删除二叉堆中最大的元素,也就是根结点,删除根结点后,将二叉树末尾的最后一个元素放置在根结点位置,然后与子节点进行比较大小,交换位置…
5.4、设计完成Heap类
public class Heap<E extends Comparable> {
private java.util.ArrayList<E> list = new java.util.ArrayList<E>();
/** Create a default heap */
public Heap() {
}
/** Create a heap from an array of objects */
public Heap(E[] objects) {
for (int i = 0; i < objects.length; i++)
add(objects[i]);
}
/** Add a new object into the heap */
public void add(E newObject) {
list.add(newObject); // Append to the heap
int currentIndex = list.size() - 1; // The index of the last node
while (currentIndex > 0) {
int parentIndex = (currentIndex - 1) / 2;
// Swap if the current object is greater than its parent
if (list.get(currentIndex).compareTo(
list.get(parentIndex)) > 0) {
E temp = list.get(currentIndex);
list.set(currentIndex, list.get(parentIndex));
list.set(parentIndex, temp);
}
else
break; // the tree is a heap now
currentIndex = parentIndex;
}
}
/** Remove the root from the heap */
public E remove() {
if (list.size() == 0) return null;
E removedObject = list.get(0);
list.set(0, list.get(list.size() - 1));
list.remove(list.size() - 1);
int currentIndex = 0;
while (currentIndex < list.size()) {
int leftChildIndex = 2 * currentIndex + 1;
int rightChildIndex = 2 * currentIndex + 2;
// Find the maximum between two children
if (leftChildIndex >= list.size()) break; // The tree is a heap
int maxIndex = leftChildIndex;
if (rightChildIndex < list.size()) {
if (list.get(maxIndex).compareTo(
list.get(rightChildIndex)) < 0) {
maxIndex = rightChildIndex;
}
}
// Swap if the current node is less than the maximum
if (list.get(currentIndex).compareTo(
list.get(maxIndex)) < 0) {
E temp = list.get(maxIndex);
list.set(maxIndex, list.get(currentIndex));
list.set(currentIndex, temp);
currentIndex = maxIndex;
}
else
break; // The tree is a heap
}
return removedObject;
}
/** Get the number of nodes in the tree */
public int getSize() {
return list.size();
}
}
5.5、使用Heap类完成排序
首先创建一个Heap类的对象,使用add方法将列表数据添加到堆中,然后使用remove方法从每次堆中提取删除最大的元素(根结点),以此完成排序。
public class HeapSort {
/** Heap sort method */
public static <E extends Comparable<E>> void heapSort(E[] list) {
// Create a Heap of integers
Heap<E> heap = new Heap<E>();
// Add elements to the heap
for (int i = 0; i < list.length; i++)
heap.add(list[i]);
// Remove elements from the heap
for (int i = list.length - 1; i >= 0; i--)
list[i] = heap.remove(); //根据二叉堆删除根结点的性质,每次提取根结点,完成排序
}
/** A test method */
public static void main(String[] args) {
Integer[] list = {2, 3, 2, 5, 6, 1, -2, 3, 14, 12};
heapSort(list);
for (int i = 0; i < list.length; i++)
System.out.print(list[i] + " ");
}
}