10 大经典排序算法之C++实现

C++写桶排序 阅读详情

简介

排序算法是《数据结构与算法》中的最基本算法之一,这是需要熟练掌握的基本知识。排序算法可以分为内部排序和外部排序,内部排序是数据在内存中进行排序;而外部排序是因为数据量非常的大,无法一次性加载完所有的数据到内存中,在排序的过程中需要访问外存,例如磁盘。常见的内部排序算法有:冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序、堆排序、计数排序、桶排序、基数排序。
各类算法的基本信息,如下表所示:

排序算法平均时间复杂度最好情况最坏情况空间复杂度排序方式稳定性
冒泡排序O(n*n)O(n)O(n*n)O(1)内排序稳定
选择排序O(n*n)O(n*n)O(n*n)O(1)内排序不稳定
插入排序O(n*n)O(n)O(n*n)O(1)内排序稳定
希尔排序O(n^1.3)O(n)O(n*n)O(1)内排序不稳定
归并排序O(n log n)O(n log n)O(n log n)O(n)外排序稳定
快速排序O(n log n)O(n log n)O(n*n)O(log n)内排序不稳定
堆排序O(n log n)O(n log n)O(n log n)O(1)内排序不稳定
计数排序O(n+k)O(n+k)O(n+k)O(k)外排序稳定
桶排序O(n+k)O(n+k)O(n*n)O(n+k)外排序稳定
基数排序O(n*k)O(n*k)O(n*k)O(n+k)外排序稳定

名词解释

  • n:数据规模
  • k:“桶”的个数
  • 内排序:占用常数内存,不占用额外内存
  • 外排序:占用额外内存
  • 稳定性:排序后2个相等剪枝的顺序和排序之前它们的顺序相同

排序算法

冒泡排序

  冒泡排序,是一种简单直观的排序算法。它是按照顺序依次进行两个元素的比较,若发现它们的顺序是相反的,则进行交换;而冒泡排序算法的终止条件是没有可交换顺序的元素。
  冒泡算法,不能说人人都会吧,但它应该是人人都很熟悉的一种排序算法,往往是在算法的第一位。其实冒泡排序还有一种优化的算法,即立一个flag,当在一趟遍历元素中没有发生交换,则证明该序列已是有序。但这种改进相对于性能的提升是没有太大的作用。
  当数据顺序是正序的时候,冒泡排序最快;当数据是反序的时候,冒泡排序是最差的。
动画演示

void sort::bubble_sort(int *array, int &length){
    /* *
     * @step
     *   1. 比较相邻的元素,若第一个比第二大,则交换它们两个;
     *   2. 对每一对相邻的元素做同样的工作,从开始第一对到结尾的最后一对。这样将会得到最大的数,并且在最后的位置;
     *   3. 如上所述,对所有的元素重复以上两步,且每次比较的长度减1;
     *   4. 没有需要对比的数之后,冒泡排序结束。
     * */

    for (int i = 0; i < length -1; ++i ) {
        int sort_lenght = length - 1 - i;
        for (int j = 0; j < sort_lenght; ++j) {
            if(array[j] > array[j+1]){
                // 数据交换 方法1
                /*int tmp = array[j+1];
                array[j+1] = array[j];
                array[j] = tmp;*/
                // 数据交换 方法2
                /*array[j+1] = array[j] + array[j+1];
                array[j] = array[j+1] - array[j];
                array[j+1] = array[j+1] - array[j];*/
                // 数据交换 方法3 有0时,不可用
                /*array[j] = array[j] ^ array[j+1];
                array[j+1] = array[j] ^ array[j+1];
                array[j] = array[j] ^ array[j+1];*/
                // 数据交换 方法4 有0时,不可用
                array[j] = array[j] * array[j+1];
                array[j+1] = array[j] / array[j+1];
                array[j] = array[j] / array[j+1];

            }
        }
    }
}

 

选择排序

  选择排序,是一种直观的排序算法之一;无论什么数据在选择排序算法中,其时间复杂度均为O(n*n)。建议在数据规模小的时候,使用选择排序。它的唯一的好处是不占用额外的内存空间。
动图演示

void sort::select_sort(int *array, int &length){
    /* *
     * @step
     *   1. 从首元素到最后元素找到最大元素,与最后的一个元素替换;
     *   2. 再从剩余的元素中找到最大元素,放在次位元素的位置;
     *   3. 重复2步骤,直至所有的元素排序完成。
     * */
    for (int i = length - 1; i >= 0; --i) {
        int index = i;
        for( int j = i - 1; j >= 0; --j){
            if(array[j] > array[index]){
                index = j;
            }
        }
        if (i == index)
            continue;
        // 交换数据
        array[i] = array[i] ^ array[index];
        array[index] = array[i] ^ array[index];
        array[i] = array[i] ^ array[index];
    }
}

 

插入排序

  相对于冒泡和选择排序,插入排序是更容易理解的,因为玩过扑克牌的人都会这招。它的原理是通过构建一个有序的序列,对于未排序的数据,在有序的序列中从前向后进行扫描,找到相应的位置进行插入。
动图演示

void sort::insert_sort(int *array, int &length){
    /* *
     * @step
     *   1. 将待排序的首元素看做有序序列;
     *   2. 将第二个元素到最后一个元素,进行排序插入到有序序列中;
     *   3. 最后一个元素插入结束,即排序结束。
     * */
    for (int i = 1; i < length; ++i) {
        int current_value = array[i];
        int j = i - 1;
        // 有序排序,方法1
        /*for (j = i - 1; j >= 0; --j){
            if (array[j] > current_value){
                array[j+1] = array[j];
            } else {
                break;
            }
        }*/
        // 有序排序,方法2
        while ( j >= 0 && array[j] > current_value) {
            array[j+1] = array[j];
            --j;
        }

        array[j+1] = current_value;
    }
}

 

希尔排序

  希尔排序,是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是插入排序的一种,它是简单插入排序经过改进后的一个更高效的版本,也称之为缩小增量排序,同时也突破O(n^2)的第一批算子。它与插入算子的不同之处在于,他会优先选择距离较远的元素进行比较。其基本思想为先将整个待排序的元素序列分割为若干子序列分别进行直接插入排序,待整个序列中的元素基本有序时,在对全体元素进行直接插入排序。

void sort::shell_sort(int *array, int &length){
    /* *
     * @step
     *   1. 选择一个增量序列t1,t2,…,tk,其中ti>tj,tk=1;
     *   2. 按增量序列个数k,对齐进行k趟排序;
     *   3. 每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m的子序列,
     *      分别对子序列进行插入排序;
     *   4. 当增量因子为1时,整个序列作为一个表来处理,其长度为整个序列的长度。
     * */

    int gap, j, i;
    for (gap = length >> 1; gap > 0; gap >>= 1) {

        for ( i = gap; i < length; ++i){

            int tmp = array[i];
            for ( j = i - gap; j >= 0 && array[j] > tmp; j -= gap) {
                array[j + gap] = array[j];
            }
            array[j+gap] = tmp;
        }
    }
}

 

归并排序

  归并排序,是一种以“分而治之”的思想(即,分治法Divide and Conquer)为基础的排序算法;其排序的实现方式有两种:

一、自上而下的递归(所有的递归方法均可以用迭代实现);
二、自上而下的迭代。

  归并排序,与选择排序一样,不受输入数据的影像,但其表现要比选择排序好很多,因而其时间复杂度始终为O(n log n),不过需要付出一定的代价——使用额外的内存空间。
动态演示

void sort::merge_sort(int *array, int &length){
    /* *
     * @step
     *   1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
     *   2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
     *   3. 比较两个指针指向的元素,选择小的元素放入到合并空间,并移动指针指到下一位置;
     *   4. 重复步骤3知道某一指针达到序列尾;
     *   5. 将另一序列剩下的所有元素直接赋值到合并序列尾。
     * */
    int* array_a = array;
    int* array_b = (int*)calloc(length, sizeof(int));
    int seg, start;
    for ( seg = 1; seg < length; seg += seg) {

        for (start = 0; start < length; start += seg * 2) {
            int left = start;
            int middle = ((start + seg) < length)? (start +seg) : length;
            int right = ((start + seg * 2) < length)? (start +seg * 2) : length;
            int index = left;
            int start_1 = left, end_1 = middle;
            int start_2 = middle, end_2 = right;
            while (start_1 < end_1 && start_2 < end_2)
                array_b[index++] = (array_a[start_1] < array_a[start_2]) ? \
                        array_a[start_1++] : array_a[start_2++];
            while (start_1 < end_1)
                array_b[index++] = array_a[start_1++];
            while (start_2 < end_2)
                array_b[index++] = array_a[start_2++];
        }

        int *temp = array_a;
        array_a = array_b;
        array_b = temp;
    }
    if (array != array_a){
        for (int i = 0; i < length; ++i)
            array_b[i] = array_a[i];
        array_b = array_a;
    }
    free(array_b);
}

 

快速排序

  快速排序,和归并排序有相似之处,均是采用“分而治之”的思想。它是由东尼●霍尔搞出来的排序算法;不同的是快速排序,是将一组元素(group)分为两个子组(sub_groups)进行排序的;且从本质上看,快速排序是递归分治法。
  快速排序,从名字上就能感受到,它存在的意义就是块;它是处理大数据最快的排序算法之一。虽然最坏情况下的时间复杂度为O(n^2),但是在大多数情况下都比平均时间复杂度为O(n log n)的排序算法表现要好;它比复杂度稳定等于O(n log n)的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序,足见其优秀的程度。
动图演示

void sort::quick_sort(int *array, int &length){
    /* *
     * @step
     *   1. 从队列中筛选出一个元素,为基准;
     *   2. 重新对序列进行排序,将比基准数小的放在前面,将比基准数大的放在后面;
     *   3. 递归地将小于基准值的元素的子数列和大于基准元素的字数列分贝进行排序;
     * */
    quick_sort_partition(array, 0, length - 1);
}
void sort::quick_sort_partition(int *array, int left, int right){
    const int current_value = array[left];
    int start = left + 1;
    int end = right;

    while (start < end){
        // 计算出比index_left大的index_max,
        while (start <= right && array[start] <= current_value)
            ++start;

        // 计算出比index_left小的index_min,
        while (end > left && array[end] > current_value)
            --end;

        // index_max, index_min的数据进行替换
        if (start <= end){
            int tmp = array[end];
            array[end] = array[start];
            array[start] = tmp;

        }
    }

    if (end > left){
        int tmp = array[left];
        array[left] = array[end];
        array[end] = tmp;
    }


    if (left < end - 1)
        this->quick_sort_partition(array, left, end - 1);

    if (end + 1 < right)
        this->quick_sort_partition(array, end + 1, right);
}

 

堆排序

  堆排序, 是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

大顶堆: 每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
小顶堆: 每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列。

在这里插入图片描述

void sort::heap_sort(int *array, int &length){
    /* *
     * @step
     *   1. 创建一个堆H[0...lenght-1]
     *   2. 把堆首(最大值)和堆尾互换;
     *   3. 把堆的尺寸缩小1,并调用shift_down(0),目的是把新的数组顶端数据调整到相应位置;
     *   4. 重复步骤2,直到堆的尺寸为1。
     * */
    // lamda表达式
    auto swap = [](int *a, int *b){
        int tmp = *a;
        *a = *b;
        *b = tmp;
    };
    // lamda表达式
    auto max_heapify = [](int* array, int start, int end){
        // 建立父节点和子节点
        int dad = start;
        int son = dad * 2 + 1;
        // 子节点在范围内作比较
        while (son <= end) {
            // 先比较两个子节点的大小,选择最大的
            if (son + 1 <= end && array[son] < array[son + 1])
                son++;
            // 如果父节点大于子节点,代表调整完成跳出函数
            if (array[dad] > array[son])
                return;
            // 否则交换父子内容再继续子节点和孙节点的比较
            else {
                int tmp = array[dad];
                array[dad] = array[son];
                array[son] = tmp;
                dad = son;
                son = dad * 2 + 1;
            }
        }
    };

    // 初始化,i从最后一个父节点开始调整;
    for (int i = length / 2 - 1; i >= 0; i--)
        max_heapify(array, i, length - 1);

    // 现将第一个元素和已经排好的元素前一位做交换,再重新调整,直到排序完成;
    for (int i = length - 1; i > 0; i--) {
        swap(&array[0], &array[i]);
        max_heapify(array, 0, i - 1);
    }

}

 

计数排序

在这里插入图片描述
  计数排序, 它的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。

void sort::count_sort(int *array, int &length){
    /* *
     * @step
     *   1. 找出待排序的数组中最大和最小的元素;
     *   2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
     *   3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
     *   4. 反向填充目标数组:将每个元素i放在新数组的第C项,每放一个元素就将C减去1。
     * */
    int *sorted_array = (int*)calloc(length, sizeof(int));
    int *count_array = (int*)calloc(length, sizeof(int));
    int i, j, k;
    for (k = 0; k < 100; k++)
        count_array[k] = 0;
    for (i = 0; i < length; i++)
        count_array[array[i]]++;
    for (k = 1; k < 100; k++)
        count_array[k] += count_array[k - 1];
    for (j = length; j > 0; j--)
        sorted_array[--count_array[array[j - 1]]] =
                array[j - 1];

    memcpy(array, sorted_array, sizeof(int) * length);
    free(sorted_array);
    free(count_array);
}

 

桶排序

  桶排序,是计数排序的升级版本;主要利用了函数的映射关系,高效与否的关键在于这个映射的确定。当输入的数据被均匀的分配到桶中时,桶排序是最快的;当数据数据被分配到一个桶中时,桶排序是最慢的。为了使桶排序更加的高效,需要做到下面的三点:

  1. 在额定空间充足的情况下,尽量增大桶的数量;
  2. 使用的映射函数能够将输入的N个数据均匀的分配到k个桶中。
  3. 在对桶中的元素进行排序时,选择哪一种比较排序算法对于性能的影像也是重要的。

在这里插入图片描述

void sort::bucket_sort(int *array, int &length){
    /* *
     * @step
     *   1. 元素分布在每一个桶中;
     *   2. 对每一个桶中的元素进行排序;
     * */
    auto insert_fun = [](list_node *head, int data)->list_node*{
        list_node dummy_node;
        auto *new_node = new list_node(data);
        list_node *pre, *curr;
        dummy_node.next_node_ = head;
        pre = &dummy_node;
        curr = head;
        while (nullptr != curr && curr->data_ <= data) {
            pre = curr;
            curr = curr->next_node_;
        }
        new_node->next_node_ = curr;
        pre->next_node_ = new_node;
        return dummy_node.next_node_;
    };

    auto merge_fun = [](list_node *head1, list_node *head2)->list_node*{
        list_node dummy_node;
        list_node *dummy = &dummy_node;
        while (nullptr != head1 && nullptr != head2) {
            if (head1->data_ <= head2->data_){
                dummy->next_node_ = head1;
                head1 = head1->next_node_;
            } else {
                dummy->next_node_ = head2;
                head2 = head2->next_node_;
            }
            dummy = dummy->next_node_;
        }
        if (nullptr != head1)   dummy->next_node_ = head1;
        if (nullptr != head2)   dummy->next_node_ = head2;

        return dummy_node.next_node_;
    };

    int BUCKET_NUM = 10;
    std::vector<list_node*> buckets(BUCKET_NUM, (list_node*)(0));
    for (int i = 0; i < length; ++i) {
        int index = array[i]/BUCKET_NUM;
        list_node *head = buckets.at(index);
        buckets.at(index) = insert_fun(head, array[i]);
    }

    list_node *head = buckets.at(0);
    for (int i = 1; i < BUCKET_NUM; ++i) {
        head = merge_fun(head, buckets.at(i));
    }

    for (int i = 0; i < length; ++i){
        array[i] = head->data_;
        head = head->next_node_;
    }
}

 

基数排序

  基数排序,是一种非比较整数排序算法,其原理是将整数按位数切割成不同的数据字,然后按每个位数分别进行比较。由于整数也可以表达字符串(名字、日期)和特定格式的浮点数(定点数),所以基数排序也不是只能使用于整数。基数排序分为两种方式:MSD,从高位开始排序;LSD,从低位开始排序。

基数排序、桶排序、计数排序比较
计数排序:每个桶只能存储单一键值;
桶排序:每个桶存储一定范围的数值;
基数排序:根据键值的每位数字来分配桶。

在这里插入图片描述

void sort::radix_sort(int *array, int &length){
    /* *
     * @step
     *   1. 根据键值的每位数字分配桶。
     * */

    auto maxbit_fun = [](int *array, int length)->int{
        int max_data = array[0];
        for (int i = 1; i < length; ++i) {
            max_data = max_data < array[i] ? array[i] : max_data;
        }

        int d = 1, p = 10;
        while (max_data >= p) {
            max_data /= 10;
            ++d;
        }
        return d;
    };

    int d = maxbit_fun(array, length);
    int *tmp = (int*)calloc(length, sizeof(int));
    int *count = (int*)calloc(10, sizeof(int));
    int count_ = 0, radix = 1;
    for ( int i = 1; i <= d; i++) {
        // 初始化计数器
        for (int j = 0; j < 10; ++j)
            count[j] = 0;
        // 统计每个桶中的记录数
        for (int j = 0; j < length; ++j) {
            count_ = (array[j] / radix) % 10;
            count[count_]++;
        }
        // 将tmp中的位置依次分配给每个桶
        for (int j = 1; j < 10; ++j) {
            count[j] = count[j - 1] + count[j];
        }
        // 将所有桶中记录依次收集到tmp中
        for (int j = length -1; j >= 0; --j) {
            count_ = (array[j] / radix) % 10;
            tmp[count[count_] - 1] = array[j];
            count[count_]--;
        }
        // 将临时数组的内容复制到array中
        for (int j = 0; j < length; ++j){
            array[j] = tmp[j];
        }
        radix = radix * 10;
    }
    free(tmp);
    free(count);
}

其余代码

// sort.h
#pragma  once

#include <iostream>

/* *
 * @brief The class of sort.
 * */
class sort {
public:
    /* *
     * @brief The class of list node, it's used to bucket sort.
     * */
    class list_node{
    public:
        explicit  list_node(int i = 0):data_(i), next_node_(nullptr){

        }
        ~list_node()= default;

        list_node* next_node_;
        int data_;
    };


    /* *
     * @brief Construction of sort class.
     * */
    sort() = default;

    /* *
     * @brief DeConstruction of sort class.
     * */
    ~sort() = default;

    /* *
     * @brief Sort type.
     * */
    enum SORT_TYPE_EN {
        BUBBLE_SORT,    ///< Bubble sort.
        INSERT_SORT,    ///< Insert sort.
        SELECT_SORT,    ///< Select sort.
        QUICK_SORT,     ///< Quick sort.
        SHELL_SORT,     ///< Shell sort.
        HEAP_SORT,      ///< Heap sort.
        MERGE_SORT,     ///< Merge sort.
        BUCKET_SORT,    ///< Bucket sort.
        COUNT_SORT,     ///< Count sort.
        RADIX_SORT      ///< Radix sort
    };

    void bubble_sort(int *array, int &length);

    void insert_sort(int *array, int &length);

    void select_sort(int *array, int &length);

    void quick_sort(int *array, int &length);

    void shell_sort(int *array, int &length);

    void heap_sort(int *array, int &length);

    void merge_sort(int *array, int &length);

    void bucket_sort(int *array, int &length);

    void count_sort(int *array, int &length);

    void radix_sort(int *array, int &length);

private:
    void quick_sort_partition(int *array, int left, int right);
}; //sort class


void sort_test(sort::SORT_TYPE_EN &type, int *array, int &length);



/*******************************************************************/
//sort.c
void sort_test(sort::SORT_TYPE_EN &type, int *array, int &length){
    sort my_sort;
    switch (type){
        case sort::BUBBLE_SORT:
            my_sort.bubble_sort(array, length);
            break;
        case sort::INSERT_SORT:
            my_sort.insert_sort(array, length);
            break;
        case sort::SELECT_SORT:
            my_sort.select_sort(array, length);
            break;
        case sort::SHELL_SORT:
            my_sort.shell_sort(array, length);
            break;
        case sort::QUICK_SORT:
            my_sort.quick_sort(array, length);
            break;
        case sort::HEAP_SORT:
            my_sort.heap_sort(array, length);
            break;
        case sort::MERGE_SORT:
            my_sort.merge_sort(array, length);
            break;
        case sort::BUCKET_SORT:
            my_sort.bucket_sort(array, length);
            break;
        case sort::COUNT_SORT:
            my_sort.count_sort(array, length);
            break;
        case sort::RADIX_SORT:
            my_sort.radix_sort(array, length);
            break;
        default:
            break;
    };
}


/*******************************************************************/
// main function
int main(int argc, char** argv){
	int array_length = 20;
	int array[array_length] = {15, 9,  7, 89, 60, 45, 3,  48, 21, 23,
	                           22, 18, 1, 90, 73, 92, 76, 20, 79, 76};
	// set sort type
	sort::SORT_TYPE_EN sort_type = sort::RADIX_SORT;
	sort_test(sort_type, array, array_length);
	
	// print sorted data
	for (int i = 0; i < array_length; ++i){
	    std::cout << array[i] << " " ;
	}
	std::cout << std::endl;
	return 0;
}
C++程序基础(10):C++打擂法和三个数排序 阅读详情

相关推荐

经典排序算法C++实现(10种)

C++实现经典排序算法插入排序希尔排序(缩小增量排序)选择排序堆排序冒泡排序冒泡排序的原理:快速排序合并排序折中排序新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章U...

weixin_42023936的博客 3233

数据结构入门

1、哈希(Hash) 满足一个’key’对应一个’value’的结构就是hash,比如http请求和响应的第二部分。 2、计数排序 比较排序的时间复杂度是nlogn,n*关于2的对数 伪代码数组的length是最大下标+1 计数排序适用于容易确定范围的数组 计数排序必须有一个Hash作为工具 计数排序无法对小数和负数进行排序 3、桶排序 将数组分到有限数量的桶里。每个桶再个别排序(有可能再使用别的...

weixin_43729368的博客 418

C++实现八大经典排序算法

希尔排序(Shell Sort)是一种基于插入排序的算法,通过将原始数据分成若干个子序列进行局部插入排序来达到整个序列的排序效果。这种排序方法由D.L.Shell于1959年提出,最初被称为“缩小增量排序”,后来人们将其命名为希尔排序。希尔排序的基本思想是将待排序数组分割成若干子序列,每个子序列由相同间隔的元素组成,然后对每个子序列进行插入排序。随着排序过程的不断深入,间隔逐渐减小,最终间隔减至1,整个数组变成一个序列进行普通插入排序。

weixin_34064233的博客 814

c++桶排序(刚学也能看懂)

桶排序是什么 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。简言之,将值为i的元素放入i号桶,最后依次把桶里的元素倒出来。 怎么样,是不是很“简单?” ...

我的博客 2万+

阿里系acw_sc__v3滑块验证码逆向分析与实战破解

本文深入解析阿里系acw_sc__v3滑块验证码的核心机制与逆向破解方法。通过分析加密参数生成、轨迹验证模块和动态加密策略,提供完整的自动化破解方案,包括设备指纹生成、缺口识别和轨迹加密等关键技术。文章还分享了常见问题的调试技巧,帮助开发者应对阿里系验证码的复杂防护体系。

wdx012345的博客 1830

手把手教你用.NET Reactor 7.3.0保护跨平台.NET应用(含macOS/Rider配置)

本文详细介绍了如何使用.NET Reactor 7.3.0为跨平台.NET应用提供代码保护。文章重点涵盖了在macOS环境下的GUI工具安装、与JetBrains Rider的深度集成配置,并针对Avalonia UI框架提供了专项保护策略和避坑指南,帮助开发者有效防止代码被反编译和破解。

coffee的博客 594

c++ 桶排序(看这一篇就够了)

桶排序(Bucket Sort)又称箱排序,是一种比较常用的排序算法。其算法原理是将数组分到有限数量的桶里,再对每个桶分别排好序(可以是递归使用桶排序,也可以是使用其他排序算法将每个桶分别排好序),最后一次将每个桶中排好序的数输出。

Lucas55555555的博客 4187

【Collibra 驱动 IPD 数据血缘治理】:三层图谱分层展示体系与全链路追踪的技术业务实践

(应用级/数据级/字段级)是理解复杂数据流动的核心手段。其价值不仅体现在可视化的直观性,更在于通过。技术保障血缘不可篡改性,进一步提升IPD数据治理的可靠性。,解决了跨层级血缘分析的性能与可用性矛盾。数据血缘图谱要素定义(字节跳动/腾讯云/信安标委)实现对IPD数据的精准追踪,而数据血缘图谱的。分层交互设计标准(智慧城市数据中台规范)Collibra技术文档(2024)字段级血缘的挑战与解决路径。自动优化血缘路径,并深化。字段级血缘技术实现方案。Collibra通过。图数据库性能优化原理。

百态·数智思维 | 聚焦大数据、量化与未来AI 1244

10大经典排序算法实战:gh_mirrors/algorithms2/Algorithms项目详解

gh_mirrors/algorithms2/Algorithms项目是一个全面的算法代码仓库,提供了多种经典排序算法的实现,帮助开发者深入理解排序原理并应用于实际项目中。本文将详解项目中的10大经典排序算法,为新手和普通用户提供清晰易懂的实战指南。 ## 一、冒泡排序:简单直观的基础排序法 冒泡排序是最基础的排序算法之一,通过重复遍历要排序的数组,一次比较两个元素,如果它们的顺序错误就把它们

gitblog_02266的博客 411

WorkBuddy 集成 飞书CLI,全程10分钟,丝滑无比,老板要注意了...

飞书CLI实测:10分钟实现AI操控飞书办公 飞书CLI作为命令行工具,让用户通过简单命令完成飞书各项操作。本文记录了从安装到使用的完整过程:一键安装仅需10分钟,支持200多条命令覆盖飞书全部功能,与AI结合后可实现自然语言办公。实测中成功用语音指令创建了7天发文计划日程,验证了其便捷性。虽然首次认证存在超时问题,但整体体验流畅。该工具将复杂操作简化为自然语言指令,大幅提升办公效率,特别适合需要频繁使用飞书的用户。后续还将探索更多自动化办公场景。

三棱球的专栏 1142

Android 集成Chrome 浏览器内核 Crosswalk

Crosswalk 内核的兴起与消亡 Android 4.4 版本之前,使用的是基于 androidWebKit 的 WebView 但实际上,由于 Android 的碎片化问题(大量存在不同的 Android 系统版本,并且各个厂商对内置应用进行定制化,有可能用的不是最新的浏览器内核)。这就导致 WebView 在真实环境中对 API 的支持根本无迹可寻,越发混乱。 随着混合开发的兴起,前端对 ...

司马懿的西山居 2万+

10个数冒泡排序流程图_10大排序算法的简洁代码实现

本文用C++尽可能简洁得实现了10大经典必知必会的排序算法,并对其中的一些算法特点比如稳定性、时间复杂度等进行了一定的说明。本文总结表如下,“其他备注”的具体内容在文章下有写出来。他们的简洁代码实现和测试脚本如下(从小到大排序):#include <stdio.h> #include <vector> #include <algorithm> #include ...

weixin_39564755的博客 840

Neo4j 智能供应链应用源代码简析

本文简析Neo4j智能供应链应用的源代码,让你也可以快速开发自己的供应链应用。

Neo4j 开发者博客 1679

6大经典排序算法 C++ 实现对比:冒泡/选择/插入/快排/归并/堆排序 10万数据实测

本文详细对比了6大经典排序算法(冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序)在C++中的实现,并通过10万数据实测分析其性能表现。结果显示,快速排序在大多数情况下表现最优,而插入排序在小规模数据中效率最高。文章还提供了工程实践中的选择建议,帮助开发者根据数据特性和环境限制选择合适的排序算法。

defkaug153461的博客 429

二十八.国民技术MCU开发之UID获取与应用

在国民NT MCU中均有一个96位和128位的唯一设备标识符,其中UCID128 位, UID 为 96 位。手册中描述的作用是:通常用来做为序列号或作为密码,在编写闪存时,将此唯一标识与软件加解密算法相结合,进一步提高代码在闪存存储器内的安全性,也可用于激活带安全功能的自举程序(SecureBootloader)。UCID 和 UID,遵守国民技术芯片序列号定义,它包含芯片生产及版本相关信息。

AIoT深度探索者 | 嵌入式系统架构师 深耕物联网(IoT)与人工智能(AI)融合技术,聚焦​​边缘计算、图像开发、低功耗通信协议​​,致力于智能硬件,关注我获取最新技术文章信息与海量资源~ 1676

【Unity实战100例】Unity循环UI界面切换卡片功能

功能包括:可以设置半径,高度,速度,元素数量用户可以根据自己的实际需求接入 制作思路:创建每个元素对应的虚拟点,通过旋转管理这些虚拟点,然后把旋转信息和位置信息同步给实际的元素

纯技术流日常开发商业开发记录总结等 7717

C++之冒泡排序

用冒泡法对10个整数由大到小排序,10个整数用cin输入  冒泡排序顾名思义像冒泡泡一样排序,从头冒到尾。首先,一次比较两个元素,如果他们的顺序错误就把他们的位置换一下,然后在比较下一组,直到没有需要交换的,这时候说明已经排序完成。  它的算法复杂度:如果他本来就排好序了,这说明只需要扫描一趟就可以完成排序,此时需要比较n-1个数,算法复杂度为O(n);如果数列是反序的,那么这时需要扫描n-1趟,...

lufei0315的博客 2414

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

十大经典排序算法最强总结(转)

转自:https://blog.youkuaiyun.com/qq_32534441/article/details/88709571 有冒泡排序、插入排序、选择排序、快速排序、希尔排序、归并排序、堆排序、基数排序、桶排序、计数排序 ...

jjhhfb的博客 1043

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

十大经典排序算法(动图演示C++实现)

参考:https://www.cnblogs.com/onepixel/articles/7674659.html 十大经典排序算法(动图演示C++实现) 0、算法概述 0.1 算法分类 十种常见排序算法可以分为两大类: (选泡插,快归堆希统计基) 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。 非比较类排...

zhangsy_csdn的博客 1万+

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

用C++实现十大经典排序算法

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。

billy的博客 1万+

C++实现十大排序算法

今天我们来用C++实现一下经典的十大排序算法 具体代码与文件可访问我的GitHub地址获取 https://github.com/liuzuoping/Algorithms PS:欢迎star 1 冒泡排序 冒泡排序无疑是最为出名的排序算法之一,从序列的一端开始往另一端冒泡(你可以从左往右冒泡,也可以从右往左冒泡,看心情),依次比较相邻的两个数的大小(到底是比大还是比小也看你心情)。 (无序区...

liuzuoping的博客 1万+

十大经典排序算法及C++实现

十大经典排序算法 1、冒泡排序 步骤 从头开始,每次比较两元素,若大者在前,则交换两元素,直至数组末尾,此时最大元素为数组最后的元素; 重复以上步骤,从头开始至上一轮比较的末尾元素; 性质 稳定算法; 代码 // 冒泡排序 void bubbleSort(vector&amp;lt;int&amp;gt;&amp;amp; array) { for (size_t i = 0; i &amp;lt; array...

kuaizi_sophia的博客 8549

十大经典排序算法(C++代码实现)

文章目录0、算法概述0.1 算法分类0.2 时间复杂度0.3 相关概念1、冒泡排序1.1 算法描述1.2 动图演示1.3 C++代码实现2、选择排序(Selection Sort)2.1 算法描述2.2 动图演示2.3 C++代码实现2.4 算法分析3、插入排序(Insertion Sort)3.1 算法描述3.2 动图演示3.2 C++代码实现4、希尔排序(Shell Sort)4.1 算法描述4.2 动图演示4.3 C++代码实现4.4 算法分析5、归并排序(Merge Sort)5.1 算法描述5.

将~军的博客 1862

算法大总结之----10大经典排序算法(从小到大排列)

1. 冒泡排序 冒泡排序,顾名思义,就是出头的被排序。其算法复杂度为O(n2n^{2}n2),空间复杂度为O(111)。 1.1. 算法讲解 将第j个元素和后面的元素依次对比,如果大于序列为j+1的元素,就进行交换。 作为对比的基础元素j取值范围为"0 => size - 2"。因为j + 1不可超过size - 1。因而,需要进行对比的j有size - 1个,这个组别用字母i表示。 当排...

Frank的博客 1万+

c 语言从大到小排序算法,10 大经典排序算法(动图演示+ C 语言代码)

原标题:10 大经典排序算法(动图演示+ C 语言代码)来源:C语言与CPP编程以前也零零碎碎发过一些排序算法,但排版都不太好,又重新整理一次,排序算法是数据结构的重要部分,系统地学习很有必要。时间、空间复杂度比较排序算法平均时间复杂度最差时间复杂度空间复杂度数据对象稳定性冒泡排序O(n2)O(n2)O(1)稳定选择排序O(n2)O(n2)O(1)数组不稳定、链表稳定插入排序O(n2)O(n2)O...

weixin_32139147的博客 3303

[C++]七大经典排序算法详解(代码实现+解析)

各种排序算法动图解析请参考 各种排序算法复杂度对比 冒泡排序法 冒泡排序是所有排序算法中相对简单且容易理解的算法,它的核心思想:通过for循环不断遍历需要排序的元素,依次比较相邻的两个元素,若不满足指定的顺序(可以从大到小排序,也可以反过来),就交换两个元素,直至完成排序。 1.比较相邻的元素。如果第一个比第二个大,就交换它们两个; 2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数; 3.针对所有的元素重复以上的步骤,除了最后一个; 4.重复步骤1~3,直

cpb____的博客 1万+
上一篇: C++设计模式之外观模式(十)
下一篇: KMP算法详解之C++
一杯盐水
博客等级 码龄10年 62粉丝 59原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值