排序

1.从未排序序列中依次取出元素与已排序序列中的元素进行比较,将其放入已排序序列的正确位置上的方法,这种排序方法称为( 插入排序)。

插入排序基本思想:每一步将一个待排序的数据插入到前面已经排好序的有序序列中,直到插完所有元素为止。

插入排序的代码实现:

void StraightSort(int *arr,int len){
    int tmp; // 用于暂存当前元素的值
    int i; // 外层循环计数器
    int j; // 内层循环计数器

    for (i = 1; i < len; i++){ // 遍历数组,从第二个元素开始
        tmp = arr[i]; // 将当前元素的值暂存到tmp变量中
        for (j = i - 1; j >= 0 && arr[j] > tmp; j--){ // 内层循环用于将当前元素插入到已排序的序列中的正确位置
            arr[j + 1] = arr[j]; // 如果前一个元素比当前元素大,则将前一个元素后移一位
        }
        arr[j + 1] = tmp; // 将当前元素插入到正确位置
    }
}

 

希尔排序(shell排序)基本思想:希尔排序是把序列按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量的逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个序列恰好被分为一组,算法便终止。

希尔排序需要定义一个增量,这里选择增量为gap=length/2,缩小增量以gap=gap/2的方式,这个增量可以用一个序列来表示,{n/2,(n/2)/2....1},称为增量序列,这个增量是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。

希尔排序代码如下:

// Shell排序算法,对数组arr进行排序,数组长度为len
void ShellSort(int *arr, int len) {
    // 使用希尔增量进行分组
    for (int gap = len/2; gap > 0; gap = gap/2) {
        // 对每个分组进行插入排序
        for (int i = gap; i < len; i++) {
            int j = i;
            // 插入排序
            while (j - gap >= 0 && arr[j] < arr[j - gap]) {
                Swap(arr, j, j - gap); // 调用Swap函数交换元素
                j = j - gap;
            }
        }
    }
}

归并排序基本思想:归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

void merge_sort(int q[], int l, int r)
{
    //递归的终止情况
    if(l >= r) return;

    //第一步:分成子问题
    int mid = l + r >> 1;

    //第二步:递归处理子问题
    merge_sort(q, l, mid ), merge_sort(q, mid + 1, r);

    //第三步:合并子问题
    int k = 0, i = l, j = mid + 1, tmp[r - l + 1];
    while(i <= mid && j <= r)
        if(q[i] <= q[j]) tmp[k++] = q[i++];
        else tmp[k++] = q[j++];
    while(i <= mid) tmp[k++] = q[i++];
    while(j <= r) tmp[k++] = q[j++];

    for(k = 0, i = l; i <= r; k++, i++) q[i] = tmp[k];
}

 

冒泡排序的基本思想就是:从无序序列头部开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到了无序队列的队尾,从而成为有序序列的一部分;下一次继续这个过程,直到所有数据元素都排好序。

算法的核心在于每次通过两两比较交换位置,选出剩余无序序列里最大(小)的数据元素放到队尾。

冒泡排序的代码:

void bubble_sort(int arr[], int len) {
    int i, j;
    for (i = 0; i < len - 1; i++)
        for (j = 0; j < len - 1 - i; j++)
            if (arr[j] > arr[j + 1])
                swap(arr[j], arr[j + 1]);
}

选择排序的思想:利用线性查找搜索出待排序列中的最小(或最大)元素,并将它移动到最前面,每完成一次遍历,都会使一个元素在正确位置,即第i趟排序后,前面i个元素在正确位置。

选择排序的代码:

// 选择排序
    // 每次找到一个最小的 放在正确的位置
    public void selectsort(int[] a) {
        int k = 0;
        int temp = 0;
        for (int i = 0; i < a.length - 1; i++) {//i控制每趟循环,从第一个元素开始
            k = i;//第i趟,k取出第i个数据与后边的数据进行比较(假设k此时为最小元素)
            for (int j = i; j < a.length; j++) {//内层循环用于找出最小元素
                if (a[j] < a[k]) {
                    k = j;//k用来记录最小元素的下标

                }
            }

            temp = a[i];
            a[i] = a[k];
            a[k] = temp;//将最小数据与待排序列的第一个元素交换

        }
        for (int num : a) {
            System.out.print(num + " ");
        }
    }

 

快速排序属于分治算法,分治算法都有三步:分成子问题  递归处理子问题  子问题合并

快速排序的代码:

void quick_sort(int q[], int l, int r)
{
    //递归的终止情况
    if(l >= r) return;

    //第一步:分成子问题
    int i = l - 1, j = r + 1, x = q[l + r >> 1];
    while(i < j)
    {
        do i++; while(q[i] < x);
        do j--; while(q[j] > x);
        if(i < j) swap(q[i], q[j]);
    }

    //第二步:递归处理子问题
    quick_sort(q, l, j), quick_sort(q, j + 1, r);

    //第三步:子问题合并.快排这一步不需要操作,但归并排序的核心在这一步骤
}

 

 

 

 

2.从未排序序列中挑选元素,并将其依次放入已排序序列(初始时为空)的一端的方法,称为(选择排序)。

 

3.对n个不同的关键字由小到大进行冒泡排序,在下列( 从大到小排列好的)情况下比较的次数最多。

 

4.快速排序在下列( 被排序的数据完全无序)情况下最易发挥其长处。

被排序的数据中含有多个相同排序码

被排序的数据已基本有序

被排序的数据完全无序

被排序的数据中的最大值和最小值相差悬殊

5.对n个不同的排序码进行冒泡排序,在元素无序的情况下比较的次数最多为(n(n-1)/2)。

 

6.对n个关键字作快速排序,在最坏情况下,算法的时间复杂度是(O(n2))。

 

7.

若一组记录的排序码为(46, 79,56,38,40,84),则利用快速排序的方法,以第一个记录为基准得到的一次划分结果为( 40,38,46,56,79,84)。

先从中间分割

 双指针是一个办法先i指向46,j指向84;

 i指向46,j指向40所以调换;

i指向79,j指向46所以调换;

i指向46,j指向38所以调换;

i指向56,j指向46所以调换;

结果如上。

8.

下列关键字序列中,( d)是堆。

A.

16,72,31,23,94,53

B.

94,23,31,72,16,53

C.

16,53,23,94,31,72

D.

16,23,53,31,94,72

小顶堆,将所有数据序列按完全二叉树从根开始放,如果所有分支都小于或者等于孩子结点关键码,就是小顶堆,反之,如果所有分支结点的关键码大于或者等于孩子结点关键码,则为大顶堆

 

9.堆是一种( 选择)排序。

选择排序分为直接选择排序和堆排序。

堆排序的基本思想是:1、将带排序的序列构造成一个大顶堆,根据大顶堆的性质,当前堆的根节点(堆顶)就是序列中最大的元素;

                                    2、将堆顶元素和最后一个元素交换,然后将剩下的节点重新构造成一个大顶堆;

                                    3、重复步骤2,如此反复,从第一次构建大顶堆开始,每一次构建,我们都能获得一个序列的最大值,然后把它放到大顶堆的尾部。最后,就得到一个有序的序列了。

堆排序代码:

public class HeapSort {
 
    public static void heapSort(int[] arr) {
        if (arr == null || arr.length == 0) {
            return;
        }
        int len = arr.length;
        // 构建大顶堆,这里其实就是把待排序序列,变成一个大顶堆结构的数组
        buildMaxHeap(arr, len);
 
        // 交换堆顶和当前末尾的节点,重置大顶堆
        for (int i = len - 1; i > 0; i--) {
            swap(arr, 0, i);
            len--;
            heapify(arr, 0, len);
        }
    }
 
    private static void buildMaxHeap(int[] arr, int len) {
        // 从最后一个非叶节点开始向前遍历,调整节点性质,使之成为大顶堆
        for (int i = (int)Math.floor(len / 2) - 1; i >= 0; i--) {
            heapify(arr, i, len);
        }
    }
 
    private static void heapify(int[] arr, int i, int len) {
        // 先根据堆性质,找出它左右节点的索引
        int left = 2 * i + 1;
        int right = 2 * i + 2;
        // 默认当前节点(父节点)是最大值。
        int largestIndex = i;
        if (left < len && arr[left] > arr[largestIndex]) {
            // 如果有左节点,并且左节点的值更大,更新最大值的索引
            largestIndex = left;
        }
        if (right < len && arr[right] > arr[largestIndex]) {
            // 如果有右节点,并且右节点的值更大,更新最大值的索引
            largestIndex = right;
        }
 
        if (largestIndex != i) {
            // 如果最大值不是当前非叶子节点的值,那么就把当前节点和最大值的子节点值互换
            swap(arr, i, largestIndex);
            // 因为互换之后,子节点的值变了,如果该子节点也有自己的子节点,仍需要再次调整。
            heapify(arr, largestIndex, len);
        }
    }
 
    private static void swap (int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

10.堆的形状是一棵(完全二叉树 )。

11.若一组记录的排序码为(46,79,56,38,40,84),则利用堆排序的方法建立的初始堆为( 84,79,56,38,40,46)。

 

12.下述几种排序方法中,要求内存最大的是(c )。

希尔排序

B.

快速排序

C.

归并排序

D.

堆排序

排序、希尔排序的空间复杂度为O(1),快速排序的空间复杂度为O(log2n),归并排序的空间复杂度为O(n)。

 

 

13.

下述几种排序方法中,( c)是稳定的排序方法。

A.

希尔排序

B.

快速排序

C.

归并排序

D.

堆排序

 

14.

数据表中有10000个元素,如果仅要求求出其中最大的10个元素,则采用( d)算法最节省时间。

A.

冒泡排序

B.

快速排序

C.

简单选择排序

D.

堆排序

堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。

 

15.)下列排序算法中,( a)不能保证每趟排序至少能将一个元素放到其最终的位置上。

希尔排序

B.

快速排序

C.

冒泡排序

D.

堆排序

快速排序的每趟排序能将作为枢轴的元素放到最终位置;

冒泡排序的每趟排序能将最大或最小的元素放到最终位置;

堆排序的每趟排序能将最大或最小的元素放到最终位置。

posted @ 2023-12-15 15:11  艾鑫4646  阅读(25)  评论(0编辑  收藏  举报