排序(更新中)

排序

首先假设:①数据是整数 ②存储在数组中 ③ 升序排序

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] + " ");
  }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值