当前位置: 首页 > news >正文

六大排序详讲(直接插入排序+希尔排序+选择排序+堆排序+冒泡排序+快速排序)

文章目录

  • 排序
    • 一、 排序的概念
      • 1.排序:
      • 2.稳定性:
      • 3.内部排序:
      • 4.外部排序:
    • 二、插入排序
      • 1.直接插入排序
      • 2.希尔排序
    • 三、选择排序
      • 1.直接选择排序
          • 方法一
          • 方法二
          • 直接插入排序和直接排序的区别
      • 2.堆排序
    • 四、交换排序
      • 1.冒泡排序
      • 2.快速排序
          • 1.挖坑法
          • 2.Hoare法
          • 3.前后指针法
          • 4.快速排序的优化
            • 方法一:随机选取基准值
            • 方法二:三数取中法选基准值
            • 方法三:递归到最小区间时、用插入排序
          • 5.快速排序非递归实现

排序


一、 排序的概念

1.排序:

  • 一组数据按递增/递减排序

2.稳定性:

在这里插入图片描述

  • 待排序的序列中,存在多个相同的关键字,拍完序后,相对次序保持不变,就是稳定的

3.内部排序:

  • 数据元素全部放在内存中的排序

4.外部排序:

  • 数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序

二、插入排序

1.直接插入排序

在这里插入图片描述

和整理扑克牌类似,将乱序的牌,按值的大小,插入整理好的顺序当中

从头开始,比最后一个小的话依次向前挪,直到大于之前牌时,进行插入

在这里插入图片描述

1.如果只有一个值,则这个值有序,所以插入排序, i 从下标1开始,把后面的无序值插入到前面的有序当中

2.j = i-1,是i的前一个数,先用tmp将 i位置的值(要插入的值)先存起来,比较tmp和j位置的值

3.如果tmp的值比 j位置的值小,说明要向前插入到有序的值中,把 j位置的值后移,移动到 j+1的位置,覆盖掉 i 的值

4.j 下标向前移动一位,再次和 tmp 比较

5.如果tmp的值比 j 位置的值大,说明找到了要插入的位置就在当前j位置之后,把tmp存的值,放到 j+1的位置

6.如果tmp中存的值比有序的值都小,j位置的值依次向后移动一位,j不停减1,直到排到第一位的数移动到第二位,j的下标从0移动到-1,循环结束,最后将tmp中存的值,存放到 j+1的位置,也就是0下标

    public void insertSort(int[] array) {for (int i = 1; i < array.length; i++) {int tmp = array[i];//tmp存储i的值int j = i - 1;for (; j >= 0; j--) {if (tmp < array[j]) {array[j + 1] = array[j];} else {// array[j+1] = tmp;break;}}array[j + 1] = tmp;}}

插入就是为了维护前面的有序

  • 元素越接近有序,直接插入排序算法的时间效率越高

  • 时间复杂度O( N 2 )

  • 空间复杂度O ( 1 )

  • 稳定性:稳定

    如果一个排序是稳定的,可以改变实现为不稳定的

    如果是不稳定的排序,则没有办法改变

2.希尔排序

在这里插入图片描述

希尔排序shellSort 叫缩小增量排序,是对直接插入排序的优化,先分组,对每组插入排序,让整体逐渐有序

利用了插入排序元素越有序越快的特点

在这里插入图片描述

  • 先确定一个整数,把待排序数分成多个组,每个组中的数距离相同,
  • 对每一组进行排序,然后再次分组排序,减少分组数,组数多,每组数据就少
  • 找到分组数=1时,基本有序了,只需要再排一次插入排序即可

一开始组数多,每组数据少,可以保证效率

随着组数的减少,每组数据变多,数据越来越有序,同样保证了效率

到达1分组之前,前面的排序都是预排序

    public static void shellSort2(int[] array) {int gap = array.length;while (gap > 1) { //gap>1时缩小增量gap /= 2;//直接在循环内进行最后一次排序shell(array, gap);}}/**** 希尔排序* 时间复杂度O(N^1.3---N^1.5)* @param array*/public static void shellSort1(int[] array) {int gap = array.length;while (gap > 1) { //gap>1时缩小增量shell(array, gap);gap /= 2;//gap==1时不进入循环,再循环为再次排序}shell(array, gap);//组数为1时,进行插入排序}public static void shell(int[] arr, int gap) {//本质上还是插入排序,但是i和j的位置相差为组间距for (int i = gap ; i < arr.length; i++) {int tmp = arr[i];int j = i-gap;for (; j >=0; j -= gap) {if (tmp<arr[j]){arr[j+gap] = arr[j];}else {break;}}arr[j+gap] = tmp;}}
  • 时间复杂度:O( N^1.3 ^) ---- O( N^1.5 ^)
  • 空间复杂的:O(1)
  • 稳定性:不稳定

三、选择排序

在这里插入图片描述

  • 在待排序序列中,找到最小值(大)的下标,和排好序的末尾交换,放到待排序列的开头,直到全部待排序元素排完

1.直接选择排序

在这里插入图片描述

方法一

    /*** 选择排序** @param array*/public static void selectSort(int[] array) {for (int i = 0; i < array.length; i++) {int minIndex = i;for (int j = i + 1; j < array.length; j++) {//找最小值if (array[j] < array[minIndex]) {minIndex = j;//只要比minIndex小,放进去}}//循环走完后,minIndex存的就是当前未排序的最小值//将当前i的值和找到的最小值进行交换swap(array,i,minIndex);}}public static void swap(int[] array, int i, int j) {int tmp = array[i];array[i] = array[j];array[j] = tmp;}

1.遍历数组长度,i从0开始

2.每次循环,都由minIndex = i 来记录最小值的下标

3.j 从i+1开始遍历,只要比记录的最小值小,就让minIndex记录。找到未排序中的最小值,进行交换

4.如果遍历完后,未排序中没有比minIndex存的值小,i的值就是最小值,i++;

  • 效率低, 如果较为有序的序列,在交换时会破坏有序性
  • 时间复杂度:O ( N2 )
  • 空间复杂的:O ( 1 )
  • 稳定性:不稳定
方法二
  • 上面的方法,只是先选出最小的值,然后和i的位置交换,

  • 进行优化:在遍历时选出最大值和最小值,和收尾进行交换

在这里插入图片描述

   /*** 选择排序---选最大值和最小值** @param array*/public static void selectSort2(int[] array) {int left = 0;int right = array.length - 1;while (left < right) {int minIndex = left;int maxIndex = left;//选出最大值和最小值for (int i = left + 1; i <= right; i++) {if (array[i] > array[maxIndex]) {maxIndex = i;}if (array[i] < array[minIndex]) {minIndex = i;}}//用最大值和最小值交换首位swap(array, left, minIndex);//把left和最小值交换//如果left恰好就是最大值,就有可能把最大值换到minIndex的位置if(left == maxIndex){maxIndex = minIndex;//最大值位置不是left了,而是换到了minIndex}swap(array, right, maxIndex);left++;right--;}}

1.在遍历的过程中,选出最大值的下标和最小值的下标

2.将left和最小值进行交换

3.如果left恰好为最大值,left和最小值交换完成后,最大值就在原来最小值的位置上,

4.maxIndex = minIndex,修正最大值的位置

4.将right和最大值进行交换

直接插入排序和直接排序的区别
  • 和插入排序不同的是,插入排序会持续对已排序的数进行比较,把合适的数放在合适的位置
  • 直接选择排序就是不断找到最小的值,依次放在排好序的末尾,不干预排好的序列

2.堆排序

  • 时间复杂度: O( N * log N)
  • 空间复杂的:O (1)
  • 升序:建大堆

  • 降序:建小堆

  • 在这里插入图片描述

将一组数据从小到大排序 ——> 建立大根堆

为什么不用小根堆:小根堆只能保证,根比左右小,不能保证左右孩子的大小顺序,并且要求对数组本身进行排序

  • 大根堆,保证堆顶元素是最大值,最大值跟最后一个元素交换,将最大的放在最后,usedSize–;
  • 向下调整:调整0下标的树,维护大根堆,最大值继续交换到最后一个有效元素的位置
  • 从后往前,从大到小依次排列,保证在原来数组本身进行排序
    /*** 堆排序* 时间复杂度: N*logN* 空间复杂的:o(1)** @param array*/public static void heapSort(int[] array) {createBigHeap(array);//创建大根堆int end = array.length-1;while (end>0){swap(array,0,end);//堆顶元素和末尾互换shiftDown(array,0,end);//维护大根堆end--;}}/*** 创建大根堆** @param array*/public static void createBigHeap(int[] array) {//最后一个结点的下标 = array.length - 1//它的父亲结点的下标就为array.length - 1 - 1) / 2for (int parent = (array.length - 1 - 1) / 2; parent >= 0; parent--) {shiftDown(array, parent, array.length);}}/*** 向下调整** @param array* @param parent* @param len*///向下调整,每棵树从父结点向下走public static void shiftDown(int[] array, int parent, int len) {int child = parent * 2 + 1;while (child < len) {//child < len:最起码要有一个左孩子if (child + 1 < len && array[child] < array[child + 1]) {child++;}//child + 1<len:保证一定有右孩子的情况下,和右孩子比较//拿到子节点的最大值if (array[child] > array[parent]) {swap(array, child, parent);parent = child;//交换完成后,让parent结点等于等于当前child结点child = 2 * parent + 1;//重新求子节点的位置,再次进入循环交换} else {break;//比父结点小,结束循环}}}
  • 时间复杂度: O( N * log 2N)
  • 空间复杂的:O (1)
  • 稳定性:不稳定

四、交换排序

  • 根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置
  • 将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

1.冒泡排序

在这里插入图片描述

    /*** 冒泡排序* 时间复杂度 n^2* 空间复杂度  1* @param array*/public static void bubbleSort(int[]array){for (int i = 0; i < array.length-1; i++) {//趟数boolean flg =false;for (int j = 0; j < array.length-1-i; j++) {if (array[j]>array[j+1]){swap(array,j,j+1);flg = true;}}if (flg == false){return;}}}

1.遍历 i 代表交换的趟数,遍历 j 进行两两交换

2.j < array.length-1-i 是对于趟数的优化,每走一趟,交换就少一次

3.boolean flg =false;当两两交换时,flg变为true

4.进一步优化:如果遍历完,没发生交换,flg还是false,直接返回,排序结束

  • 时间复杂度:O ( N2 )
  • 空间复杂度:O ( 1 )
  • 稳定性:稳定

2.快速排序

  • 时间复杂度:

    最好情况:O (N*log2N) :树的高度为log2N,每一层都是N

    最坏情况:O (N2):有序、逆序的情况下,没有左树,只有右树,单分支树,树的高度是N,每一层都是N

  • 空间复杂的:

    最好情况:O (log2N):满二叉树(均匀分割待排序的序列,效率最高)树高为 log2N

    最坏情况:O(N):单分支树,树高为N

  • 稳定性:不稳定

  • 二叉树结构的交换排序方法

  • 任取一个待排序元素作为基准值,把序列一分为二,左子序都比基准值小,右子序都比基准值大,左右两边再重复进行

在这里插入图片描述

  • 左边找比基准值大的,右边找比基准值小的
1.挖坑法

在这里插入图片描述

  • 基准值位置挖一个坑,后面找一个比基准值小的把坑埋上
  • 前面找一个比基准值大的,埋后面的坑
  • 当l==r时,把基准值填入剩下的坑中

在这里插入图片描述

  • 左右两边重复进行上述步骤,直到排完为止
  • 左右两边都以同样的方法进行划分,运用递归来实现
    /*** 快速排序* 时间复杂度:N*log~2~N* 空间复杂度* * @param array*/public static void quickSort(int[] array) {quick(array, 0, array.length - 1);}private static void quick(int[] array, int start, int end) {if (start >= end) {return;//结束条件// start == end,说明只剩一个了,是有序的,返回//start > end ,说明此时的基准值在开头或者末尾//在开头:start不变,end=pivot-1,start > end ,end=-1 没有左树//在结尾:end不变,start = pivot+1,start > end,超出索引,没有右树}//不断递归quickint pivot = partition(array, start, end);// 进行排序,划分找到pivot//然后递归划分法左边,递归划分的右边quick(array, start, pivot - 1);quick(array, pivot + 1, end);}// ---挖坑法  划分,返回基准值private static int partition(int[] array, int left, int right) {int tmp = array[left];//挖一个坑,取left位置为基准值while (left < right) {//在右边找一个比基准值小的把坑填上while (left < right && array[right] >= tmp) {//防止越界right--;}array[left] = array[right];//找到比tmp小的数,填坑,//在左边找一个比tmp大的值,填到右边的坑while (left < right && array[left] <= tmp) {//防止越界left++;}array[right] = array[left];}//如果相遇了,退出循环array[left] = tmp;//填坑return left;}
  • 先划分序列,递归左边,然后再递归右边

  • 递归结束条件:

    start == end时,说明只剩一个了,是有序的,返回
    start > end 时 ,说明此时的基准值在开头或者末尾

    如果基准值在开头:start不变,end=pivot-1,start > end ,end=-1 没有左树
    如果基准值在结尾:end不变,start = pivot+1,start > end,超出索引,没有右树


2.Hoare法

在这里插入图片描述

  • 不同的方法,找出基准值,排的序列是不一样的

在这里插入图片描述

  • i记录基准值一开始在left位置的下标
  • r找到比基准值小的停下来,l找到比基准值大的停下来,互相交换
  • l和r相遇的时候,把i 记录基准值的初始下标和相遇位置交换

以左边为基准,先找右边再找左边,相遇的位置就是以右边为基准的值,要比基准小,才能交换

    /*** Hoare法 划分排序找基准值* @param array* @param left* @param right* @return*/private static int partition2(int[] array, int left, int right) {int tmp = array[left];int i  = left;//记录基准值一开始在left位置的下标while (left < right) {while (left < right && array[right] >= tmp) {right--;}while (left < right && array[left] <= tmp) {left++;}swap(array,left,right);}swap(array,i,left);return left;}
3.前后指针法

在这里插入图片描述

在这里插入图片描述

  • prev记录了比key小的最后一个位置
  • cur去找比key值小的,找到后,放到prev的下一个位置
  • 最后找到基准值,并且基准值的左边都比它小,右边都比他大
    /*** 前后指针法,划分排序找基准值** @param array* @param left* @param right* @return*/private static int partition3(int[] array, int left, int right) {int prev = left; //prev从left位置开始,left为当前的基准值int cur = left + 1;//cur在prev的后一个while (cur <= right) {//遍历完当前数组段if (array[cur] < array[left] && array[++prev] != array[cur]) {//只要cur指向的值小于left位置的基准值//并且prev++后不等于cur的值swap(array, cur, prev);//将cur和prev位置的值交换//cur++;}//如果cur的值大于基准值,或者prev下一位的值等于cur,cur后移cur++;}//cur越界,循环结束,最后,交换基准值和prev位置的值//prev记录的就是比基准值小的最后一个数swap(array, prev, left);return prev;//prev为基准值}
4.快速排序的优化
  • 时间复杂度:

    最好情况:O (N*log2N) :树的高度为log2N,每一层都是N

    最坏情况:O (N2):有序、逆序的情况下,没有左树,只有右树,单分支树,树的高度是N,每一层都是N

  • 空间复杂的:

    最好情况:O (log2N):满二叉树(均匀分割待排序的序列,效率最高)树高为 log2N

    最坏情况:O(N):单分支树,树高为N

  • 稳定性:不稳定

  • 快速排序有可能发生栈溢出异常,需要进行优化

  • 所以要能均匀分割待排序的序列

递归的次数多了,会导致栈溢出,所以优化的方向就是减少递归的次数

在最坏情况下,比如顺序,基准值都取自左边,本身没有左树

方法一:随机选取基准值

看人品,有概率

方法二:三数取中法选基准值

三数:第一个数、中间的数、最后一个数 ,在这三个数中,选出中等值

有可能会变成二分查找 ,避免了出现最坏情况,从中值来比较排序,左右树都有

    public static void quickSort(int[] array) {quick2(array, 0, array.length - 1);}private static void quick2(int[] array, int start, int end) {if (start >= end) {return;//结束条件}//三数取中法int index = midThree(array, start, end);//选出的数和开头交换swap(array,index,start);int pivot = partition(array, start, end);// 进行排序,划分找到pivot//然后递归划分法左边,递归划分的右边quick2(array, start, pivot - 1);quick2(array, pivot + 1, end);}/*** 三数取中* @param array* @param left* @param right* @return*/private static int midThree(int[] array, int left, int right) {int mid = (left + right) / 2;if (array[left] < array[right]) {if (array[mid] < array[left]) {return left;} else if (array[mid] > array[right]) {return right;} else {return mid;}} else {if (array[mid] < array[right]) {return right;} else if (array[mid] > array[left]) {return left;} else {return mid;}}}
方法三:递归到最小区间时、用插入排序

进一步优化:减少递归的次数:

  • 把快排的递归想象成二叉树,最后两层包含了大部分数,我们要减少这部分的递归

  • 前几次的找基准值排序,导致后面几层趋于有序,用直接插入法来排序,进一步提高效率,有点像希尔排序

如果树的高度为h,最后一层就有 2 h-1 个结点 ,后两层占了绝大部分

设置条件:end-start+1 就是当前待排序列的长度,如果小于等于某个较小的值,直接采用插入排序来排剩下的

 private static void quick2(int[] array, int start, int end) {if (start >= end) {return;//结束条件}//优化----减少递归的次数if(end-start+1<=20){//如果当前数列的长度,小于=15的时候,// 用插入排序,然后退出insertSortQ(array,start,end);return;}//三数取中法int index = midThree(array, start, end);swap(array,index,start);int pivot = partition(array, start, end);// 进行排序,划分找到pivot//然后递归划分法左边,递归划分的右边quick2(array, start, pivot - 1);quick2(array, pivot + 1, end);}/*** 插入排序---来排剩下的待排部分,给定需要的区间*/private static void insertSortQ(int[] array,int left,int right) {for (int i = left+1; i <= right; i++) {int tmp = array[i];int j = i - 1;for (; j >= left; j--) {if (array[j] > tmp) {array[j + 1] = array[j];} else {break;}}array[j + 1] = tmp;}}
5.快速排序非递归实现
  • 1.通过使用栈来实现
  • 2.每次找到基准值后,把两段序列的开头和末尾压栈
  • 3.从栈顶取出两个元素作为新序列的首尾,再次找基准值
  • 4.找到基准值后,如果右边有一个元素,不进栈,有两个元素的才能进栈
  • 5.pivot< end-1:证明右边有两个元素,pivot>s+1:证明左边有两个元素
  • 6.栈为空的时候,排完元素
      /*** 非递归实现快速排序** @param array*/public static void quickSortNonRecursive(int[] array) {Deque<Integer> stack = new LinkedList<>();//利用栈来实现int left = 0;int right = array.length - 1;//先找到基准值int pivot = partition(array, left, right);//左边有两个元素时,根据基准值进栈if (pivot > left + 1) {stack.push(left);stack.push(pivot - 1);}//有边有两个元素时,根据基准值进栈if (pivot < right - 1) {stack.push(pivot + 1);stack.push(right);}//栈不为空的时候,取两个栈顶元素做为区间//再次进栈出栈while (!stack.isEmpty()) {right = stack.pop();left = stack.pop();pivot = partition(array, left, right);//左边有两个元素时,根据基准值进栈if (pivot > left + 1) {stack.push(left);stack.push(pivot - 1);}//有边有两个元素时,根据基准值进栈if (pivot < right - 1) {stack.push(pivot + 1);stack.push(right);}}}

点击移步博客主页,欢迎光临~

偷cyk的图

相关文章:

六大排序详讲(直接插入排序+希尔排序+选择排序+堆排序+冒泡排序+快速排序)

文章目录 排序一、 排序的概念1.排序&#xff1a;2.稳定性&#xff1a;3.内部排序&#xff1a;4.外部排序&#xff1a; 二、插入排序1.直接插入排序2.希尔排序 三、选择排序1.直接选择排序方法一方法二直接插入排序和直接排序的区别 2.堆排序 四、交换排序1.冒泡排序2.快速排序…...

Clickhouse初认识

技术主题-clickhouse 一什么是clickHouse 1&#xff09;本质上就是一款数据库管理系统&#xff0c;能提供海量数据的存储和检索 2&#xff09;基于列存储&#xff0c;数据是按照列进行存储的&#xff08;数据格式一样&#xff0c;方便进行压缩&#xff09; 3&#xff09;具备…...

网络安全项目简介

安全项⽬ 基线检查 更改缺省的账户检查Guest用户是否禁用密码复杂性密码长度账户口令的生存期口令重复次数口令认证失败次数口令到期提示域成员禁用更改机器账户密码限制匿名用户连接共享账户检查远程关机授权是否开启默认文件共享每个用户是否遵循最小权限原则adminstrator账…...

CSDN每日一题学习训练——Python版(N皇后 II、买卖股票的最佳时机 II、编程通过键盘输入每一位运动员)

版本说明 当前版本号[20231120]。 版本修改说明20231120初版 目录 文章目录 版本说明目录N皇后 II题目解题思路代码思路参考代码 买卖股票的最佳时机 II题目解题思路代码思路参考代码 编程通过键盘输入每一位运动员题目解题思路代码思路参考代码 N皇后 II 题目 n 皇后问题…...

semodule工具详解(1)

本文内容参考&#xff1a; semodule(8) - Linux manual page https://linux.die.net/man/8/semodule 1. 介绍 名称 semoudule —— 管理SELinux策略模块。 简介 semodule [options]... MODE [MODES]... 描述 semodule是用于管理SELinux策略模块的工具&#xff0c;包括安装…...

用百度AI大模型给头像换风格

心血来潮想尝试尝试AI小应用&#xff0c;给图片加个风格&#xff08;例如微信头像&#xff09;&#xff0c;于是有了这篇简短的教程 目录 1. 领取免费资源2. 在应用列表创建应用3. 在线API调试4. 效果对比 1. 领取免费资源 网站&#xff1a;百度智能云 百度给提供了很多AIGC的…...

从入门到精通,mac电脑录屏软件使用教程!

“mac电脑怎么录屏呀&#xff0c;刚买了一台mac电脑&#xff0c;用了几个月感觉挺流畅的&#xff0c;最近因为工作原因&#xff0c;需要用到录屏功能&#xff0c;但是我不会操作&#xff0c;想问问大家有没有简单易懂的录屏教程&#xff0c;谢谢啦。” 在日常生活中&#xff0…...

Nginx(反向代理,负载均衡,动静分离)

反向代理 Nginx反向代理是一种将客户端请求转发给后端服务器的技术&#xff0c;即反向代理服务器。在这种架构中&#xff0c;客户端请求首先到达Nginx服务器&#xff0c;然后由Nginx服务器将请求转发给后端服务器&#xff0c;后端服务器响应请求&#xff0c;并将响应传递回Ngi…...

【Spring】SpringBoot的扩展点之ApplicationContextInitializer

简介 其实spring启动步骤中最早可以进行扩展的是实现ApplicationContextInitializer接口。来看看这个接口的注释。 package org.springframework.context;/*** Callback interface for initializing a Spring {link ConfigurableApplicationContext}* prior to being {linkpl…...

哈希表HashTable

散列表&#xff08;Hash table&#xff0c;也叫哈希表&#xff09;&#xff0c;是根据键&#xff08;Key&#xff09;而直接访问在内存存储位置的数据结构。 哈希表中关键码就是数组的索引下标&#xff0c;然后通过下标直接访问数组中的元素&#xff0c;复杂度O(1) 哈希表本质…...

【软件测试】一位优秀测试工程师具备哪些知识和经验?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 根据观察&#xf…...

MongoDB相关基础操作(库、集合、文档)

文章目录 一、库的相关操作1、查看数据库2、查看当前库3、创建数据库4、删除数据库 二、集合的相关操作1、查看库中所有集合2、创建集合2.1、显示创建2.2、隐式创建 3、删除集合 三、文档的相关操作1、插入文档1.1、插入单条文档1.2、插入多条文档1.3、脚本方式 2、查询文档3、…...

进程和线程( Process and Thread)

目录 一、操作系统&#xff08;Operating System&#xff09; 操作系统的定位 二、 什么是进程/任务&#xff08;Process/Task&#xff09; 1.进程控制块抽象(PCB Process Control Block) 2.PCB中重要的属性 3.并发编程 三、线程&#xff08;Thread&#xff09; 1. 线程是…...

linux apache安装及虚拟主机配置

centos 安装apache&#xff0c; yum install httpd 将httpd.conf中的ServerName 前面的 # 去掉。 apache 2.2 的虚拟机的配置放置在conf/extra/httpd-vhosts.conf 中 apache 虚拟主机设置 a2enmod rewrite sudo vim 000-default 修改 ServerName *:80 <VirtualHost *…...

基于Spring Boot 框架的试卷自动生成系统的设计与实现

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。你想解决的问题&#xff0c;今天给大家介绍…...

开发《猫咪攻略》小游戏的意义

开发《猫咪攻略》小游戏的意义有以下几点&#xff1a; 学习和掌握游戏开发的基本技能&#xff1a;通过开发《猫咪攻略》小游戏&#xff0c;可以学习和掌握游戏开发的基本技能&#xff0c;包括游戏策划、游戏设计、游戏编程和游戏测试等方面的技能。增强对猫咪的了解和认识&…...

hadoop、hive、DBeaver的环境搭建及使用

本文主要介绍hadoop、hive的结构及使用&#xff0c;具体的操作步骤见最后的附件&#xff1b; hadoop提供大数据的存储、资源调度、计算&#xff0c;分为三个模块&#xff1a;HDFS、YRAN、MapReduce HDFS提供数据的分布式存储&#xff0c;分为三个节点NameNode,DataNode,Second…...

Linux上通过SSL/TLS和start tls连接到LDAP服务器(附C++代码实现认证流程)

一&#xff0c;大致流程。 1.首先在Linux上搭建一个LDAP服务器 2.在LDAP服务器上安装CA证书&#xff0c;服务器证书&#xff0c;因为SSL/TLS&#xff0c;start tls都属于机密通信&#xff0c;需要客户端和服务器都存在一个相同的证书认证双方的身份。3.安装phpldapadmin工具&am…...

HarmonyOS ArkTS List组件和Grid组件的使用(五)

简介 ArkUI提供了List组件和Grid组件&#xff0c;开发者使用List和Grid组件能够很轻松的完成一些列表页面。常见的列表有线性列表&#xff08;List列表&#xff09;和网格布局&#xff08;Grid列表&#xff09;&#xff1a; List组件的使用 List是很常用的滚动类容器组件&…...

考研思想政治理论大纲

一:马克思主义基本原理概论 (一)马克思主义是关于无产阶级和人类解放的科学 1、马克思主义的创立和发展 马克思主义的含义。马克思主义产生的经济社会根源、实践基础和思想渊源、马克思主义的创立、马克思主义在实践中的发展 2、马克思主义的鲜明特征 马克思主义科学性和革命…...

构建AI代码解释器:从沙箱安全到智能体工作流实践

1. 项目概述&#xff1a;当代码有了“思考”的能力 最近在GitHub上看到一个挺有意思的项目&#xff0c;叫 haseeb-heaven/code-interpreter 。光看名字&#xff0c;你可能会联想到OpenAI的Code Interpreter&#xff0c;或者一些AI辅助编程工具。没错&#xff0c;这个项目的核…...

Linux awk 命令:文本处理的瑞士军刀

awk 是 Linux 下最强大的文本处理工具之一&#xff0c;名字取自三位创始人 Aho、Weinberger、Kernighan 的姓氏首字母。很多人只用它做简单的列提取&#xff0c;其实 awk 的能力远不止于此。 awk 的核心模型 awk 的工作流程可以概括为&#xff1a; awk pattern { action } f…...

精通MagiskBoot:Android启动镜像修改与Root权限获取实战指南

精通MagiskBoot&#xff1a;Android启动镜像修改与Root权限获取实战指南 【免费下载链接】Magisk The Magic Mask for Android 项目地址: https://gitcode.com/GitHub_Trending/ma/Magisk MagiskBoot是Android系统定制与Root权限获取的核心工具&#xff0c;它专门处理bo…...

HKUDS开源NanoBot

概述 官网&#xff0c;HKUDS开源&#xff08;GitHub&#xff0c;42.1K Star&#xff0c;7.4K Fork&#xff09;纳米级Clawdbot&#xff08;OpenClaw&#xff09;&#xff0c;复刻Clawdbot几乎所有的核心智能体功能&#xff0c;但代码量只有4000行。 注&#xff1a;NanoBot除H…...

CHIP LAN(片式网络变压器)选型决策指南:从需求到量产

在以太网接口设计中&#xff0c;CHIP LAN&#xff08;片式网络变压器&#xff09;将传统的隔离变压器、共模扼流圈和匹配电阻整合进一个贴片封装&#xff0c;既简化了PCB布局&#xff0c;也提升了生产一致性。然而&#xff0c;选型错误并不会因为集成度提高而消失——链路不稳、…...

基于Next.js 14与Vercel AI SDK构建企业级全栈AI聊天应用

1. 项目概述&#xff1a;一个可投入生产的全栈AI聊天应用最近在GitHub上看到一个挺有意思的项目&#xff0c;叫“ChatGPT Clone”。这可不是一个简单的玩具或者演示&#xff0c;而是一个功能相当完备、可以直接部署上线的全栈AI聊天应用。它用上了当前前端领域最热门的Next.js …...

ARM缓存维护指令DC IGVAC与DC ISW详解

1. ARM缓存维护指令概述在ARMv8/9架构中&#xff0c;缓存维护指令&#xff08;Cache Maintenance Instructions&#xff09;是处理器与内存子系统交互的关键接口。这些指令允许软件直接控制缓存行为&#xff0c;确保数据一致性并优化系统性能。根据操作粒度的不同&#xff0c;A…...

AI算法在多市场环境下的合谋机制与市场分配策略研究

1. 项目概述&#xff1a;当AI成为市场中的“隐形玩家”最近几年&#xff0c;我身边不少做量化交易、电商定价或者供应链优化的朋友&#xff0c;都开始频繁地讨论一个话题&#xff1a;我们部署的AI优化算法&#xff0c;会不会在不知不觉中“串通”起来&#xff0c;形成一种新型的…...

三维分子表征学习:从不变性、等变性到高体阶方法的技术演进与实践

1. 项目概述&#xff1a;三维分子表征学习的核心挑战与演进在药物发现、材料科学和催化设计等领域&#xff0c;理解分子的三维结构如何决定其性质与功能&#xff0c;是一个根本性的科学问题。传统的实验方法耗时耗力&#xff0c;而计算模拟&#xff0c;特别是基于量子力学的计算…...

Linux内核升级翻车实录:一次由apt autoremove引发的Kernel panic及完整修复过程

Linux内核升级灾难现场&#xff1a;从Kernel Panic到系统救赎的深度解剖 那天下午的阳光透过百叶窗照进办公室&#xff0c;我像往常一样在Ubuntu终端里敲下sudo apt update && sudo apt upgrade -y&#xff0c;随后又习惯性地加上了sudo apt autoremove来清理旧包。这个…...