数据结构排序算法

1.插入排序

直接插入排序

直接插入排序(Insertion Sort)是一种简单的排序算法,其主要思想是把待排序的元素插入到已经排好序的部分中,从而得到一个新的有序序列。具体来说,它的排序过程如下:

  1. 从第二个元素开始,将其与前面的元素进行比较,如果比前面的元素小,则将其插入到合适的位置,使得前面的部分仍然有序。
  2. 对于第三个元素到最后一个元素,重复上述过程。

直接插入排序的时间复杂度为 O(n^{2}),其中 n 表示数组的长度。当数组已经有序时,时间复杂度为 O(n)。

关于比较次数,最坏情况下,即待排序的序列为逆序时,直接插入排序的比较次数最多。具体来说,对于长度为 n 的数组,最坏情况下的比较次数为 ,即大约为 \frac{n(n-1)}{2}。在最好情况下,即待排序的序列已经有序时,直接插入排序的比较次数仅为 n-1。

public void insertOrder(int arr[]){
    int i,j;
    int temp;//用于交换
    for(i=1;i<arr.length;i++){
        temp=arr[i];
        for(j=i-1;j>=0&&arr[j]>temp;j--){
            arr[j+1]=arr[j];
        }
        arr[j+1]=temp;
    }
    //while实现
    int n = arr.length;
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j = i - 1;
        // 将比 key 大的元素往后移动
        while (j >= 0 && arr[j] > key) {
           arr[j + 1] = arr[j];
           j--;
        }
        arr[j + 1] = key;
   }
}

希尔排序

希尔排序(Shell Sort)是一种改进的插入排序算法,也被称为缩小增量排序。它通过将整个待排序序列分割成若干个子序列来进行排序,逐步减小子序列的长度,最终完成排序。

希尔排序的基本思想是先将待排序序列按照一定间隔(增量)分割成若干个子序列,对每个子序列进行插入排序。然后逐步缩小增量,重复上述的子序列分割和排序过程,直到最后增量为1,即对整个序列进行插入排序。

希尔排序的核心在于选取合适的增量序列。常用的增量序列是采用 Knuth 提出的增量序列:h = 3*h + 1,其中 h 是增量,初始值可以是数组长度的一半。通过不断缩小增量的方式,可以使得希尔排序更高效地进行插入排序,因为较小的元素会快速地向前移动。

希尔排序的时间复杂度取决于增量序列的选择,一般情况下是 O(nlogn)。尽管希尔排序的性能不如快速排序或归并排序,但它对于中等规模的数据集仍然表现良好,并且相对于其他的排序算法而言,希尔排序的实现较为简单。

public void shareOrder(int arr[]){
    int i, j, temp, d;
    for(d = arr.length / 2; d >= 1; d /= 2){
        for(i = d; i < arr.length; i += d){
            temp = arr[i];
            for(j = i - d; j >= 0 && arr[j] > temp; j -= d){
                arr[j + d] = arr[j];
            }
            arr[j + d] = temp;
        }
    }
}

2.选择排序

简单选择排序

简单选择排序(Selection Sort)是一种简单直观的排序算法,其基本思想是通过不断地选择未排序部分的最小元素,将其放到已排序部分的末尾,从而逐步构建有序序列。具体来说,它的排序过程如下:

  1. 首先,找到未排序部分中的最小元素,并将其与未排序部分的第一个元素进行交换,将该最小元素放到已排序部分的末尾。
  2. 然后,再从未排序部分中找到剩余元素的最小元素,并将其与未排序部分的第一个元素进行交换,将该最小元素放到已排序部分的末尾。
  3. 重复以上步骤,直到未排序部分为空。

简单选择排序的时间复杂度为O(n^{2}),其中 n 表示数组的长度。无论输入数据的初始顺序如何,它的比较次数都是一样的。但是,选择排序每次只需要进行一次交换操作,因此相对于其他交换类排序算法(如冒泡排序),它的交换次数相对较少。

 public void selectOrder(int arr[]){
     int i,j;
     int temp;
     int min;
     for(i=0;i<arr.length;i++){
         min=i;
         //找到最小元素的下标
         for(j=1;j<arr.length;j++){
             if(arr[j]<arr[min]){
                min=j;
             }
         }
         //与未排序的第一个元素交换位置
         temp=arr[min];
         arr[min]=arr[i];
         arr[i]=temp;
    }
} 

堆排序

堆排序是一种基于堆数据结构的排序算法。在堆排序中,我们使用二叉堆(通常是最大堆)来进行排序操作。

堆是一种特殊的完全二叉树,其中每个节点的值都大于等于(或小于等于)其子节点的值。最大堆是指根节点的值大于等于其子节点的值,而最小堆是指根节点的值小于等于其子节点的值。

堆排序的基本概念如下:

  1. 构建最大堆:将待排序的数组看作一个完全二叉树,并按照从右至左、从下至上的顺序,对每个非叶子节点进行调整,使得该节点的值大于等于其子节点的值。
  2. 排序:将最大堆的堆顶元素(即数组的第一个元素)与堆的最后一个元素交换位置,然后将堆的大小减1,并对新的堆顶元素进行调整,以满足最大堆的性质。重复这个过程,直到堆的大小为1,即数组已经有序。
  3. 最终得到的数组就是按照升序排列(或降序排列)的结果。

堆排序的优点是具有较好的时间复杂度和空间复杂度:

  • 时间复杂度:堆排序的平均时间复杂度为O(nlogn),其中n是待排序数组的长度。
  • 空间复杂度:堆排序的空间复杂度为O(1),即原地排序。

需要注意的是,堆排序是一种不稳定的排序算法,即相等元素的相对顺序可能会发生改变。

private void adjustheap(int arr[], int p) {
    int temp;
    int child = p * 2 + 1; // 左孩子
    while (child < arr.length) {
        if (child + 1 < arr.length && arr[child] < arr[child + 1]) {
            child = child + 1; // 若右孩子更大,则改为右孩子
        }
        if (arr[child] > arr[p]) {
            temp = arr[child];
            arr[child] = arr[p];
            arr[p] = temp;
            p = child; // 更新p,则将从此下标继续上述操作
            child = p * 2 + 1; // 更新child
        } else {
            return; // 若此时父节点更大则不用交换
        }
    }
}

private void heapsort(int arr[]) {
    int temp;
    // 建堆从序号最大的分支节点开始向下调整
    for (int i = (arr.length - 1) / 2; i >= 0; i--) {
        adjustheap(arr, i);
    }
    for (int i = arr.length - 1; i >= 1; i--) {
        // 交换最大值与末尾的值
        temp = arr[i];
        arr[i] = arr[0];
        arr[0] = temp;
        // 重新调整最大堆
        adjustheap(arr, 0);
    }
}

3.交换排序

冒泡排序

冒泡排序(Bubble Sort)是一种简单直观的排序算法,其基本思想是重复地遍历要排序的数列,依次比较相邻的两个元素,如果它们的顺序错误就交换它们的位置,这样每一轮遍历后,最大的元素会被移动到数列的末尾。重复以上过程,直到整个数列都有序。

具体来说,它的排序过程如下:

  1. 对于长度为 n 的数列,进行 n - 1 轮遍历。
  2. 在每一轮遍历中,从第一个元素开始,依次比较相邻的两个元素,如果它们的顺序错误就交换它们的位置。
  3. 每一轮遍历结束后,最大的元素就会被移动到数列的末尾。
  4. 重复以上步骤,直到整个数列都有序。

冒泡排序的时间复杂度为O(n^{2}),其中 n 表示数组的长度

public void bubbleOrder(int arr[]){
    int i,j;
    int temp;
    Boolean isswap;
    for(i=arr.length-1;i>=0;i--){
        isswap=Boolean.FALSE;
        for(j=0;j<=i;j++){
            if(arr[j]>arr[j+1]){
               temp=arr[j];
               arr[j]=arr[j+1];
               arr[j+1]=temp;
               isswap=Boolean.TRUE;
            }
        }
        if(!isswap) return;
   }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值