十大经典排序算法【算法思想+图解+代码】【数据结构与算法笔记】

news2024/11/15 20:40:49
前言:文中大部分为本人收集整理,综合学习资料,个人理解……。希望能帮助你少掉写头发,早日走出理解的深渊。因为写作较为仓促文中内容难免会有纰漏,发现可评论区回复(无奖)。

排序(Sort)

  • 分析排序算法的执行效率、内存消耗、稳定性(应对各种极端情况的时间空间复杂度波动)

  • 有序度是数组中具有有序关系的元素对的个数

  • 完全有序的数组的有序度叫满有序度,N*(N-1)/2

  • 逆序度 = 满有序度 - 有序度

  • 排序的过程就是一种增加有序度,减少逆序度的过程,最后达到满有序度,此时说明排序完成

  • 排序是针对数据的排序,而常见数据的底层存储结构无非就是数组和链表,而这两种结构的排序实现虽然大同小异但各有各的优缺点。

补充:(和线性代数中的概念差不多)

  • 满有序度:所有排列的个数

  • 有序度:满足排序规则的排列个数

  • 逆序度:未满足排序规则的排列个数

  • 例:

  • 有集合(5,6,9,0,2)可得以下有序排列

(5,6)(5,9)、(5,0)、(5,2)

(6,9)、(6,0)、(6,2)

(9,0)、(9,2)

(0,2)

  • 以升序为排列规则得:

满有序度 = (n - 1)* n / 2 = (5 - 1) * 5 / 2 = 10

有序度 = 3 (红色标注部分)

逆有序度 = 10 - 3 = 7;

  • 有序区、无序区:已经排序完成的部分就是有序区,还未排序的部分就是无序区。

十大经典排序算法

一、冒泡排序(Bubble Sort)

排序首先明确以何种规则排序(升序或降序,本文均默认采用了升序排列)

算法思想:一组待排序数中,每次从第一个数开始将其和其后的一个数进行比较,如果前数大则交换两数,交换后后挪一个位置继续比较,每次将最大数交换至相对靠后的位置上,往复比较直到这组数的倒数第一个和倒数第二个数比较、交换结束,至此第一轮结束,我们将最大的数已经放在了最后的位置上。接下来是第二轮,还是从第一个数开始俩俩比较、交换位置,不过这次的比较次数比第二轮会少一次(因这一轮中最后的一个数已经排序完成),同理再进行第三轮(这一轮又会比第三轮少比较一次,因为这一轮汇总最后两个数已经排序完成,无需让他们参与比较)、第四轮…… 排序终止条件就是总共比较了(n-1)+(n-2)+ …… + 1次。故其时间复杂度为O(n²)(默认均为最坏情况)。

算法图解:

算法实现:

void BubbleSort(int* arr, int arrLen) {    //需要传入数组引用以及,数组长度
    int i, j;
    for(i = 0; i < arrLen - 1; ++i)        //控制比较的轮数
        for(j = 0; j < arrLen - i - 1; ++j)  //控制每轮比较次数
            if(arr[j] > arr[j+1])          //根据比较结果决定是否交换
                swap(arr, j, j+1);
}

注:所有算法的可运行程序附在文章结尾处

二、选择排序(Selection Sort)

算法思想:这个算法就是我们笔算排序用的算法。在一组数中找出最小的一个排在第一个位置,然后在剩下的数中找一个次小的排在第二位,再找剩下元素中第三小…….很简单吧。用计算机实现其实还略微有点不同,我们要在原来的位置上交换,而非重新创建一个数组。

先从头遍历整数组,必然能从中找出最小的一个(相同的找到第一个最小的就行),然后将其和原来第一个位置上的数进行交换,然后重新遍历数组。这次从

第二个位置上开始遍历(因为第一个位置上已经排序完成,第二个数之前都是有序区,其后是无序区,),再找出一个最小数,将其和第二个位置上的数交换。再重新重第三个数遍历,找出…… 直到我们将要从倒数第一个数遍历时排序也就结束了。

算法图解:

算法实现:

void SelectionSort(int* arr,int arrLen) {
    int i, j;
    int minElemIndex;    //存每一轮最小元素索引
    for(i = 0; i < arrLen; ++i) {
        minElemIndex = i;
        for(j = i + 1; j < arrLen; ++j)    //在本轮中找出最小元素
            if(arr[j] < arr[minElemIndex] )
                minElemIndex = j;     //更新最小元素索引值
        if(i != minElemIndex)     //是否有必要交换 
            swap(arr, i, minElemIndex);    //将本轮最小元素与对应位置上的元素交换
    }
}

三、插入排序(Insertion Sort)

算法思想:将原来待排序的数组划分成两个区域,即无序区和有序区,有序区开始只包含第一个元素,其右侧剩下的元素均处于无序区。每次对无序区第一个元素进行排序,即将无序区第一个元素和有序区最后一个元素比较(由后向前比较),如果比较过程中出现两者比较后需要交换位置则交换其位置,然后向前移一位继续俩俩比较,直到前面没有可以比较元素则停止,排序结束;或者出现某次比较后无需交换,则此时停止比较,排序结束。以上是一轮排序结束,每一轮结束都可以将无序区中的第一个元素排好序,然后无序区减少一个元素,有序区增加了一个元素,接着只需要用 同样的方法将屈无序区中的全部元素都排序即可。

算法图解:

算法实现:

void InsertionSort(int arr[], int arrLen) {
    int i, j;
    for (i = 1; i < arrLen; ++i)
        for (j = i; j > 0; --j)    // 从第二个位置开始判断,每次前移一位继续比较 
            if (arr[j] < arr[j - 1])    //相邻的俩俩比较 
                swap(arr, j, j - 1);    
            else
                break;
}

四、堆排序(Heap Sort)

堆(Heap):

  • 堆是一种完全二叉树

  • 特性:堆中每个节点的值都不小于(或不大于)其子树中任何节点的值

  • 分类:大顶堆(上大下小)、小顶堆(上小下大)。除此之外的堆是“不成熟”的堆,即还在堆化的路上

  • 堆化:顺着节点所在路径,向下或向上比较,然后交换节点

  • 堆的数组存储形式:

算法思想:首先将n个元素的数组构造成一个大顶堆,然后将堆顶元素(0号元素)与最后一个元素交换,这样就将最大值放在了数组最后(n-1的位置),然后把数组长度减1,再将这n-1长度的数组重新构造成大顶堆,再把堆顶元素与新长度的数组最后的元素进行交换(n-2的位置)元素交换位置,如此往复最后就能将原数组从后向前的排序完成。其难点是堆的重构部分。

算法图解:(制作粗糙,但关键在于理解)

算法实现:

//堆化:构建大顶堆
void ShiftDown(int *arr, int heapSize, int k) {
    while (2 * k + 1 < heapSize) {  // 在 k节点的所有子元素中执行一下步骤
        int i = 2 * k + 1;  // i为k的左孩子
        if (i + 1 < heapSize && (arr[i + 1] > arr[i]))  // 如果其右孩子在需排序的长度范围内,且左孩子小于右孩子
            i += 1; //该节点遍历结束,
        if (arr[k] >= arr[i])   //当k结点大于该节点终止循环
            break;
        swap(arr, k, i);    //不符合堆定义,交换元素位置
        k = i;  //更新节点交换后的位置
    }
}

void HeadSort(int *arr, int arrLen) {
    int i;
    for (i = (arrLen - 1) / 2; i >= 0; --i)
        ShiftDown(arr, arrLen, i);  // 建立初始堆
    for (i = arrLen - 1; i > 0; --i) {
        swap(arr, 0, i);    //交换首尾元素,第i次排序完成
        ShiftDown(arr, i, 0);   // 重构堆(i记录了上次发生交换的结点)
    }
}

堆排序是一种不稳定的排序算法。那什么是排序算法的稳定性?

假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

例:[1,6,3,46,5,4]经过排序算法后结果是[1,3,4,4,5,6,6],两个4和两个6的相对位置都没有发生改变,则这样的排序算法就是稳定的。还是上面的算法稍加修改代码就可以验证堆排序是不稳定的:

typedef struct {
    int id;     // 数据编号(唯一)
    int value;  // 排序字段
    /*其他字段……*/
} data;

void swap(data *arr, int i, int j) {
    data t = arr[i];    // 这里交换整个data而非排序字段
    arr[i] = arr[j];
    arr[j]= t;
}

void ShiftDown(data *arr, int heapSize, int k) {
    while (2 * k + 1 < heapSize) {
        int i = 2 * k + 1;
        if (i + 1 < heapSize && (arr[i + 1].value > arr[i].value))
            i += 1;
        if (arr[k].value >= arr[i].value)
            break;
        swap(arr, k, i);
        k = i;
    }
}

void HeadSort(data *arr, int arrLen) {
    int i;
    for (i = (arrLen - 1) / 2; i >= 0; --i)
        ShiftDown(arr, arrLen, i);
    for (i = arrLen - 1; i > 0; --i) {
        swap(arr, 0, i);
        ShiftDown(arr, i, 0);
    }
}

五、归并排序(Merge Sort)

算法思想: 归并排序采用了分治法(典型有汉诺塔问题,想了解可戳:点我看视频讲解)。首先将待排序的数组拆分成两数组,两个拆四个,直到最后每个数组都只由一个元素组成的(这样的每个数组都是有序的),然后俩俩“合并”,此合并非彼合并,我们仍需遍历两个数组,在这两个数组中的几个元素中重新排序(这个重新排序的结果需要临时保存在大小合适的新数组中),不过因为原来两个数组都是有序的,所以当我们操作完其中一个数组的全部元素后,如果另一个数组还有剩余的元素,直接将它们放在后面即可。俩俩合并最终我们得到了排序好的数组。将一个数组排序的事分成两个数组排序,而这两个数组各自又想分成俩个数组……直到最后数组只剩下一个元素(这个数组天然是有序的),这样再由下向上回归。简而言之就是同样的方法套娃,直到最后可以被很容易的解决。好一个釜底抽薪!

算法图解:

算法实现:

int Merge(int *arr, int left, int mid, int right) {
    int i = left, j = mid, index = 0;
    int *temp = (int *) malloc(sizeof(int) * (right - left));   // 创建辅助数组
    while (i < mid && j < right)
        temp[index++] = arr[i] < arr[j] ? arr[i++] : arr[j++];  // 比较大小,将较小元素并入辅助数组
    while (i < mid)     //并入左侧数组剩余元素
        temp[index++] = arr[i++];
    while (j < right)   //并入右侧数组剩余元素
        temp[index++] = arr[j++];
    for (i = 0; i < index; ++i)     //辅助数组数据写回原数组(重要)
        arr[left + i] = temp[i];
    free(temp); // 释放辅助数组内存空间
}

void MergeSort(int *arr, int left, int right) {
    // 1.递归拆分原数组
    if (right - left <= 1)  // 递归终止条件
        return;
    int mid = (left + right) / 2;     //计算区间终点
    MergeSort(arr, left, mid);  //
    MergeSort(arr, mid, right);
    // 2.排序且并归
    Merge(arr, left, mid, right);
}

六、快速排序(Quick Sort)

算法思想:同样采用分治法。首先从待排序数组中任意挑选一个元素作为基准值,然后将所有比该基准值小的数都放在其左边,大的放在右边;这样就将原来待排序的数分成了两组,但每组数据量减半;再对这两组数采取以上同样的方法,直到最后每一小组数都排好序时,全部排序完成。感觉有点像归并排序,但快速排序无序辅助数组,直接在原地就排序了(空间复杂度为O(nlogn)是因为该算法涉及递归,递归当然需要额外占用空间了,上面的归并排序空间复杂度是一样的解释)。其实可以不用递归到最深处,比如最后分组容量较小时可以对每个小分组该用冒泡,插入排序等。除此之外。快速排序的基准值选取可以很大程度上影响其算法的效率(本文取相对固定位置上的值为基准值。而一般会采用随机化,调用形式相同,但是会在正式选取基准值之前将即将定位基准值的位置上的数随机的与组内的一个数交换)。

算法图解:

算法实现:

// 分区且排序
int Partition(int *arr, int left, int right) {
    int pivot = arr[right],i = left;        //默认以每组最右元素为基准值
    for (int j = left; j < right; ++j) {    //从左向右遍历
        if (arr[j] < pivot) {
            if (i != j)
                swap(arr, i, j);    //将较小值放在靠前的位置
            i++;
        }
    }
    swap(arr, i, right);    //基准值插在最后一个较小值之后,这样其前面就是较小的分区,后面是较大的分区
    return i;   //返回新分区结点位置
}

void QuickSort(int *arr, int left, int right) {
    if (left >= right)  //参数校验
        return;
    int index = Partition(arr, left, right);    //获取新分区节点的位置(索引)
    QuickSort(arr, left, index - 1);    //左分区
    QuickSort(arr, index + 1, right);    //右分区
}

随机优化快速排序:

int Partition(int *arr, int left, int right) {
    swap(arr, right, rand() % (right - left) + left); // =====随机选取基准值=====
    int pivot = arr[right], i = left; 
    for (int j = left; j < right; ++j) { 
        if (arr[j] < pivot) {
            if (i != j)
                swap(arr, i, j);
            i++;
        }
    }
    swap(arr, i, right);   
    return i;   
}

void QuickSort(int *arr, int left, int right) {
    if (left >= right)  
        return;
    int index = Partition(arr, left, right);  
    QuickSort(arr, left, index - 1);    
    QuickSort(arr, index + 1, right);    
}

七、希尔排序(Shell Sort)

算法思想:希尔排序其实是插入排序的改版。首先我们将数组按照一定的间隔分组,比如长度为8的数组我们第一次设置的间隔就为4(一般为数组长度的一半,即同一组数中间间隔4-1个数),这样就就分成了[0],[4],[8](表示下标)、[1][5]、[2][6]、[3][7]四组,然后这四组单独排序(使用的是插入排序),排序完成后我们重新设置间隔设为2(减半),采取同样的方法,再次分组、排序。直到最后分组间隔为1,再最后一次排序之后就完成整个数组的排序工作了(可能你有疑问:既然最后间隔是1,不就是整体排序吗,那前面那么多次排序何必?其实不然,如果你稍微去研究一下插入排序的具体步骤,你就会发现它在数组相对有序是,性能是很不错的,所以前面的多次排序其实都是为了最后一步而铺垫的)。

算法图解:

算法实现:

void ShellSort(int *arr, int arrLen) {
    int i, j, group;
    for (group = arrLen / 2; group > 0; group /= 2) {   //分组
        for (i = group; i < arrLen; ++i) {      //排序遍历从分组间隔数开始(不会取到
            int temp = arr[i];
            for (j = i; j >= group && temp < arr[j - group]; j -= group)    //组内排序
                arr[j] = arr[j - group];    //就是在前面找到了一个合适的位置交换了元素,像不像插入排序??
            arr[j] = temp;
        }
    }
}

八、桶排序(Bucket Sort)

算法思想:是一种解决大文件排序的方法将数据根据大小范围分到不同的“桶”中,再对每个桶排序,最后依次倒出桶中的元素就是有序的了。应用前提:排序的数据容易划分到m个桶中,各个桶内的数据量相差不大。对用于对大文件的排序,你很清楚的直到计算机需要操作的数据都是需要先加载到内存,现在的内存也就十几、几十个G,如果要排序的文件大小远超内存大小那么如何排序呢?桶排序,先将数据分成几桶,然后依次加载每桶的数据进行排序,这样就可以把整个大文件进行排序。

算法图解:

算法实现:

比较简单,此处略。

九、计数排序(Counting Sort)

算法思想:我们直到数组的通过索引访问是很快的,那么我们就利用这一个特点,比较要排序的数字和和下标都是数字,创建一个长度为数组中最大值+1的新数组,先初始化每一个元素,将其赋0,然后遍历待排序数组,将其对应下标的元素值+1,这样一直将每一个数出现的次数都统计好。因为下标是天然有序的,然后我们从头到尾访问这个统计数字出现次数的数组,将其下标对应的数输出小标对应元素值那么多次,至此排序完成。该算法有一个明显的缺点,处理离散数据时占用空间大,还有就是“没办法对负数排序”,毕竟下标都是自然数,办法总比困难多,我们只需再求出原数组的最小值(负数。正数也行,解决最小值与0相差较大的正数数组排序),将其设置为一个偏移量。例如最小值为-8,设置其偏移量为8,即所有数在统计前先+8,这样就能让统计结果全部落在自然数范围内(当然开辟统计数组的大小就不是用最大值了,而是最大值最小值两者绝对值之和)。

算法图解:

算法实现:

void CountingSort(int *arr, int arrLen) {
    int length = GetMax(arr, arrLen) + 1, i, j, k;
    int *counting = (int *) malloc(sizeof(int) * length); //开辟一个长度为最大值+1的数组
    for (i = 0; i < arrLen; ++i)    //数组初始化
        counting[i] = 0;
    for (i = 0; i < arrLen; ++i)    //开始计数
        counting[arr[i]]++;
    for (i = 0, j = 0; j < length; ++j) {
        if (counting[j] != 0)
            for (k = 0; k < counting[j]; ++k)   //安装counting计数结果重新将数据写回数组(即排序)
                arr[i++] = j;
    }
    free(counting);
}

十、基数排序(Radix Sort)

算法思想:不管多大多小的数,都是由0~9这十个基本数字组成的,不同的数只是位数不同或同一位(权值)上的基数不同。借此,我们先从每个数的最低位(如个位)开始比较,将它们分类(借助队列),然后依次取出再比较上一位(如十位),还是同样的方法,直到最后所有数最高位均为0时排序结束。

为什么从低位到高位比较? 权值,基数的排列顺序构成了不同的数,越低位其权值越低,影响越小。所以从低位开始排,然后到高位时显然很可能会打乱前一步排序结果,但因为其权值高影响大,所以实际不会影响最终结果。例如86、49,先从高位排,8>4,所以结果为49、86,然后排低位,9>6,所以结果为49、86,显然很荒唐。

想排负数,行,同样设置偏移量,每个数都加上最小负数的绝对值,然后当做正数排就好。

算法图解:

算法实现:

/*基数排序*/
void RadixSort(int *arr, int arrLen) {
    int flag, k, weight, radix, i;
    int *temp = (int *) malloc(sizeof(int) * arrLen);     //这里是直接把双重队列用一个数组代替
    // 从低位到高位,weight表示权值
    for (weight = 1;; weight *= 10) {
        //radix就是9个基数,每次按顺序取一个基数
        for (radix = 0, k = 0; radix < 10; ++radix) {
            //遍历待排序数组,寻找特定位数上基数匹配的数
            for (i = 0, flag = 0; i < arrLen; ++i) {
                if (arr[i] / weight % 10 == radix)  //取出该数指定位置上的数与本轮拿到的基数比较
                    temp[k++] = arr[i];     //匹配后将该数写入所谓的双重队列数组(不同权值时temp数组刷新,重新写)
                if (arr[i] / weight % 10 == 0) {    //记录每次发生该位上的数字为0的次数
                    ++flag;
                    if (flag == arrLen) {   //如果出现的次数等于数组长度,上次已经比较完了最高位
                        free(temp); //释放内存占用
                        return; //算法结束
                    }
                }
            }
        }
        //将临时数组写回(保存本轮成果)
        for (int i = 0; i < arrLen; ++i)
            arr[i] = temp[i];
    }
}

最后没什么可写,分享一下自己的歌单:QQ音乐歌单

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/175567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

StudioOne6旗舰版DAW2023跨版本升级新功能介绍

PreSonus2023发布了Studio One 6旗舰级DAW的跨版本升级。他们获奖的DAW软件的这一最新版本引入了大量的新功能和增强功能&#xff0c;包括用户界面的定制选项&#xff0c;PreSonus说这使第6版成为他们迄今为止最个性化的升级。PreSonus发布了旗舰级DAW的跨版本升级&#xff0c;…

Leetcode:131. 分割回文串(C++)

目录 问题描述&#xff1a; 实现代码与解析&#xff1a; 回溯&#xff1a; 原理思路&#xff1a; 问题描述&#xff1a; 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都…

客快物流大数据项目(一百零六):实时ETL处理

文章目录 实时ETL处理 一、业务流程 二、​​

Kettle简介

一、Kettle基本介绍 Kettle(现更名为Pentaho Data Integration-Pentaho)是一款国外开源的ETL工具&#xff0c;纯java编写&#xff0c;可以在Window、Linux、Unix上运行&#xff0c;绿色无需安装。它允许你管理来自不同数据库的数据&#xff0c;通过提供一个图形化的用户环境来…

盒模型应用 改变宽高范围 改变背景覆盖范围 溢出处理 断词规则 空白处理

目录盒模型应用改变宽高范围改变背景覆盖范围溢出处理断词规则 word-break空白处理 溢出的空白处理盒模型应用 改变宽高范围 默认情况下&#xff0c;width 和 height 设置的是内容盒宽高。 页面重构师&#xff1a;将psd文件&#xff08;设计稿&#xff09;制作为静态页面 衡量…

【竞赛题】6297. 根据第 K 场考试的分数排序

题目 班里有 m 位学生&#xff0c;共计划组织 n 场考试。给你一个下标从 0 开始、大小为 m x n 的整数矩阵 score &#xff0c;其中每一行对应一位学生&#xff0c;而 score[i][j] 表示第 i 位学生在第 j 场考试取得的分数。矩阵 score 包含的整数 互不相同 。 另给你一个整数…

【机器学习】多标签分类

目录&#xff1a;多标签分类一、算法1.1 One-vs-Rest1.2 AdaBoost-MH1.3 ML-KNN一、算法 多标签分类的适用场景较为常见&#xff0c;比如&#xff0c;一份歌单可能既属于标签旅行也属于标签驾车。有别于多分类分类&#xff0c;多标签分类中每个标签不是互斥的。多标签分类算法…

Python使用K-means聚类分析

Python使用K-means聚类分析 文章目录Python使用K-means聚类分析介绍1.集群标签作为特征一、k-均值聚类二、示例 - 加州住房2.KMeans总结介绍 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 本文将使用所谓的无监督学习算法。 无监督算法不使用目标&#xff…

软件测试复习11:自动化测试

专栏&#xff1a;《软件测试》 个性签&#xff1a;顺境不惰&#xff0c;逆境不馁&#xff0c;以心制境&#xff0c;万事可成。——曾国藩 文章目录自动化测试的前提自动化测试的过程自动化测试的5个级别自动化测试的局限自动化测试的前提 自动化测试可以很好地代替人&#xf…

Facebook运营策略中的SEO优化:10个提示

在过去的一年中&#xff0c; Facebook上的品牌营销预算激增&#xff0c;这就是为什么许多人正在使用 Facebook来推广其业务。然而&#xff0c;并非所有新品牌都可以通过在社交媒体上进行成功的 SEO优化而获得成功。如果你想在 Facebook上销售你的产品或服务&#xff0c;你需要从…

2022年终总结——从打工到创业的转折

目录一、机会的创造和紧抓二、时间线的诉说1.1-4月份&#xff0c;在外面工作的过程中也在考虑这个事情&#xff1b;是在一个自己刚熟悉的金融行业学习提升&#xff1f;还是回归到自己铺垫了很久的教育行业深耕&#xff1f;2.5月份&#xff0c;孤身一人奔赴创业之路&#xff1b;…

《深入浅出计算机组成原理》学习笔记 Day7

电路基础1. 使用电信号的优势2. 继电器3. “与”、“或”、“非”参考1. 使用电信号的优势 从信息编码的角度来说&#xff0c;金、鼓、灯塔、烽火台类似电报的二进制编码。 电报传输的信号有两种&#xff0c;一种是短促的点信号&#xff08;dot 信号&#xff09;&#xff0c;…

【Go基础】包与工程化和常用标准库

文章目录一、包与工程化1. 用go mod管理工程2. 包引入规则3. init调用链4. 可见性二、常用标准库1. 数学计算2. 时间函数3. I/O操作4. 编码一、包与工程化 1. 用go mod管理工程 初始化项目&#xff1a; go mod init $module_name$module_name和目录名可以不一样 上述命令会生…

OpenMP 原子指令设计与实现

OpenMP 原子指令设计与实现 前言 在本篇文章当中主要与大家分享一下 openmp 当中的原子指令 atomic&#xff0c;分析 #pragma omp atomic 在背后究竟做了什么&#xff0c;编译器是如何处理这条指令的。 为什么需要原子指令 加入现在有两个线程分别执行在 CPU0 和 CPU1&…

LeetCode102_102. 二叉树的层序遍历

LeetCode102_102. 二叉树的层序遍历 一、描述 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff…

java抽象类和接口2023026

抽象类&#xff1a; 当编写一个类时&#xff0c;常常会为该类定义一些方法&#xff0c;这些方法用以描述该类的行为方式&#xff0c;那么这些方法都有具体的方法体。但在某些情况下&#xff0c;某个父类只是知道其子类应该包含怎样的方法&#xff0c;但无法准确地知道这些子类如…

使用阿里云服务器ECS 及一些问题白话阐述

阿里云服务器ECS的申请流程 首先登录阿里云官网 https://www.aliyun.com/ 查看产品文档学习观看然后看完后 大致有了了解后 我们按照我下面梳理的流程走首先购买阿里云服务器点击产品 下拉找到 云服务器ECS 然后点击进入进入到ECS的页面如果你是新人可以享受优惠购买因为还是比…

Linux常用命令——strace命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) strace 跟踪系统调用和信号 补充说明 strace命令是一个集诊断、调试、统计与一体的工具&#xff0c;我们可以使用strace对应用的系统调用和信号传递的跟踪结果来对应用进行分析&#xff0c;以达到解决问题或者…

go test的简单使用

go test go 集成了比较好用的test测试命令&#xff0c;该命令可以测试Go代码的可用性。 前奏 该文所需的项目目录结构为: example||---------function.go||---------function_test.go||---------go.modfunction.go文件是我们写用户代码的地方&#xff0c;function_test.go文…

力扣(LeetCode)388. 文件的最长绝对路径(2023.01.21)

假设有一个同时存储文件和目录的文件系统。下图展示了文件系统的一个示例&#xff1a; 这里将 dir 作为根目录中的唯一目录。dir 包含两个子目录 subdir1 和 subdir2 。subdir1 包含文件 file1.ext 和子目录 subsubdir1&#xff1b;subdir2 包含子目录 subsubdir2&#xff0c;…