java 数据结构 排序算法

目录

排序

插入排序

直接插入排序

希尔排序( 缩小增量排序 ):

直接选择排序

堆排序

交换排序

冒泡排序

快速排序递归

Hoare法

挖坑法

前后指针法

快速排序优化

快速排序非递归

归并排序

归并排序非递归

排序算法复杂度及稳定性分析

计数排序


排序(Sort)

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来

的操作,所有的排序默认都是从小到大排序

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录

的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]

之前,则称这种排序算法是稳定的;否则称为不稳定的。

内部排序:例如定义了一个数组,在哪开辟的呢?当程序运行起来在内存上开辟的,在内存中存储

的,那我们叫内部排序

外部排序:例如你要排序的数据在磁盘上存储着,那叫外部排序,例如如果有10个G数据,你的运行

内存只有8个G,只能借助外部来进行排序

常见的排序算法


插入排序

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的

记录插入完为止,得到一个新的有序序列 实际中我们玩扑克牌时,就用了插入排序的思想

直接插入排序

思路:设置两个变量记录,设置一个temp变量存储i下标的元素,j从下标为i-1的开始,i从下标为1

的开始,i递增,j递减,每次temp跟j下标的进行比较,如果小于,j+1下标的位置放入temp,如果大于

就不变还是放在i下标的位置

代码实现:

    //直接插入排序
    //适用于:带排序已经基本趋于有序
    //稳定性:稳定的,如果是本身就是稳定的排序,一定可以实现不稳定的排序
    public static void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int temp = array[i];
            int j = i - 1;
            for (; j >= 0; j--) {
                //这里加不加等号 和稳定有关系
                if (temp < array[j]) {
                    array[j + 1] = array[j];
                } else {
                    //array[j + 1] = temp;
                    break;
                }
            }
            array[j + 1] = temp;
        }
    }

疑问:

1.为什么array[j + 1] = array[j];j+1不能写i?当i=5,j=4,循环一次后,如果满足条件,这时候i还是5我们要改的是j+1下标

2.为什么array[j + 1] = temp;j+1不能写i?因为内部循环j结束后会递减,会到-1下标

直接插入排序的特性总结:

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

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1),它是一种稳定的排序算法

4. 稳定性:稳定


希尔排序( 缩小增量排序 ):

先进行分组,然后进行插入排序,希尔排序,gap就是组数

图解

思路:先选定一个整数,把待排序文件中所有记录分成多个组,所有距离为gap的记录分在同一组

内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有

记录在统一组内排好序。

代码实现:

    //希尔排序
    //稳定性:不稳定
    public static void shellSort(int[] array) {
        int gap = array.length;
        while (gap > 1) {
            gap /= 2;
            shell(array, gap);
        }
    }

    /**
     * 对每组进行插入排序
     *
     * @param array
     * @param gap
     */
    public static void shell(int[] array, int gap) {
        //为什么不是i+=gap,因为图中有红色的线要进行排序,蓝色的线也要进行排序
        for (int i = gap; i < array.length; i++) {
            int temp = array[i];
            int j = i - gap;
            for (; j >= 0; j -= gap) {
                if (array[j] > temp) {
                    array[j + gap] = array[j];
                } else {
                    break;
                }
            }
            array[j + gap] = temp;
        }
    }

希尔排序的特性总结:

1. 希尔排序是对直接插入排序的优化

2. 当gap > 1时都是预排序,目的是让数组更接近于有序。

当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比

3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定

小结:希尔排序的速度比直接插入排序的速度快


直接选择排序

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部

待排序的数据元素排完 

图解

思路:设置一个变量minIndex用来记录i元素的下标,一开始存放的是i下标,然后跟j比较,j小的话

就更新里面的下标,内部循环结束后交换元素,因为内部比完了才知道哪个最小,i++,以此类推

代码实现:

   /**
     * 选择排序
     * 时间复杂度:O(n^2)
     * 空间复杂度:
     * 稳定性:
     *
     * @param array
     */
    public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            //记录i元素的下标
            int minIndex = i;
            for (int j = i + 1; j < array.length; j++) {
                if (array[j] < array[minIndex]) {
                    //如果j元素比i元素小,更新minIndex里面的下标
                    minIndex = j;
                }
            }
            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;
    }

第二种方法实现

图解

思路:设置left和right变量,一个从第一个开始一个从最后一个开始,minIndex和maxIndex一开始

都是left,从第二个元素开始遍历,如果小于minIndex的值,我们就更新minIndex的下标,如果大于

的话我们更新maxIndex的下标,循环结束后,我们交换,把左边的元素都放小的,右边元素放大

注意:在交换右边元素的时候要注意如果一开始第一个是最大值,交换过后,如图中的9就到了

maxIndex的位置,28到了minIndex的位置,然后轮到maxIndex交换的时候这个9就跑到最后去了

代码实现:

    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[minIndex]) {
                    minIndex = i;
                }
                if (array[i] > array[maxIndex]) {
                    maxIndex = i;
                }
            }
            swap(array, left, minIndex);
            //防止 第一个是最大值 如果和最小的一换 最大值就跑到了原来最小值的位置
            if (maxIndex == left) {
                maxIndex = minIndex;
            }
            swap(array, right, maxIndex);
            left++;
            right--;
        }
    }

直接选择排序的特性总结

1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1)

4. 稳定性:不稳定

小总结:直接插入排序和选择排序的区别,直插设置变量存的是元素,选择存的是下标

直插可以直接进行交换,而选择要更新变量存的下标,得出最小值下标进行交换


堆排序

我在上一篇文章有讲解 java 数据结构 优先级队列(PriorityQueue)-CSDN博客


交换排序

冒泡排序

优化版实现:

    //冒泡排序
    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 - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    swap(array, j, j + 1);
                    flg = true;
                }
            }
            if (flg == false) {
                break;
            }
        }
    }

冒泡排序的特性总结:

1. 冒泡排序是一种非常容易理解的排序

2. 时间复杂度:O(N^2)

3. 空间复杂度:O(1)

4. 稳定性:稳定


快速排序递归

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序

列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,

直到所有元素都排列在相应位置上为止

缺点:数据多的时候会数据溢出,处理逆序不太好

Hoare法

图解

思路:Hoare法就是right从右边开始找比基准值小的,左边开始找比基准值大的,两个都满足就交

换,相遇了的时候就把相遇下标的元素跟基准值下标的元素进行交换

完整思路:这个做法先把最左边的作为基准值,然后尾巴找出比基准值小的元素然后停住,头找出

比基准值大的元素然后停住,两个进行交换,然后尾接着找比基准值小的元素,头接着找比基准值

大的元素,直到相遇,然后和基准值交换位置,这时候基准值的左边都是比它小的,右边都是比它

大的,然后递归,左边从头到基准值的位置-1开始,右边从基准值+1到尾开始,以此类推,直到,

头大于尾巴开始归,跟前序与中序的归一样,这里是大于等于就归

代码实现:

    //快速排序
    //Hoare版
    public static void quickSort(int[] array) {
        quick(array, 0, array.length - 1);
    }

    public static void quick(int[] array, int start, int end) {
        //如果大于等于,说明找完了
        if (start >= end) {
            return;
        }

        //找出基准值
        int div = quickNeedle(array, start, end);
        quick(array, start, div - 1);
        quick(array, div + 1, end);
    }

     public static int partitionHoare(int[] array, int left, int right) {
        int tmp = array[left];
        //这个i用来记录第一个下标元素
        //因为最后要跟第一个下标元素进行交换
        int i = 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;
    }

挖坑法

图解

思路:先把第一个下标的元素挖出来存到一个变量里,然后开始循环,右边开始找如果找到比左边

小的,我们就把那个坑填上,然后更新一下坑的位置,然后开始左边如果找到比第一次存的元素大

的,我们去把刚才的坑填上,然后更新一下坑的位置,以此类推,最后左右相遇,把坑填上存一开

始存的第一个下标的元素,也就是我们的基准值

代码实现:

    //挖坑法
    public static int partitionHole(int[] array, int left, int right) {
        int tmp = array[left];
        while (left < right) {
            while (left < right && array[right] >= tmp) {
                right--;
            }
            //把坑填上
            array[left] = array[right];
            while (left < right && array[left] <= tmp) {
                left++;
            }
            array[right] = array[left];
        }
        //走到一起的时候这个坑空着 把坑填上我们的基准值
        array[left] = tmp;
        return tmp;
    }

疑问:

这两个问题,第一个问题如果少了等于(<=tmp)如果第一个元素和最后一个元素一样的话,会

死循环。

第二个为什么不能从左边开始,下图和上图对比一下,上图可以看出左边开始的话left

和right会停留在6这个位置,9出现在第一个位置这就不符合左边的都是小于基准值

的,排序也不能变有序。

小总结:

Hoare法就是right从右边开始找比基准值小的,左边开始找比基准值大的,两个都满足就交换,相

遇了的时候就把相遇下标的元素跟基准值下标的元素进行交换

挖坑法就是先把基准值挖掉,然后从右边开始找比基准值小的,找到就填入一开始基准值的坑,填

了这个坑那右边这个位置不就空了,然后左边找比基准值大的,找到就填刚才右边空的坑,以此类

推,然后相遇了的时候,这个位置的坑填入基准值


前后指针法

图解

思路:设置一个变量prev记录left下标也就是上面图中key的位置,然后设置一个变量cur记录left+1

的下标,while循环当cur走到比数组长度长就停止,然后每次cur下标的元素跟left下标也就是最左

边的元素进行比较,如果小于并且prev走到下一步所对应的下标元素跟cur的元素相同,cur和prev

元素就进行交换,否则cur往前走,循环结束后,prev停留的位置的元素跟最左边也就是left的元素

进行交换

代码实现:

   //前后指针法
    public static int quickNeedle(int[] array, int left, int right) {
        int prev = left;
        //cur从头下标+1开始走
        int cur = left + 1;
        //当cur走出right结束
        while (cur <= right) {
            //cur下标元素要小于头下标元素 并且
            if (array[cur] < array[left] && array[++prev] != array[cur]) {
                swap(array, prev, cur);
            }
            //没有cur就往前走
            cur++;
        }
        //走完了 prev下标的元素和头下标的元素进行交换 这个就是我们的基准值
        swap(array, prev, left);
        return prev;
    }


快速排序优化

1. 三数取中法选key

2. 递归到小的子区间时,可以考虑使用插入排序

思路:就比如说1-10这个有序的数组,把头和尾拿出来,中间的下标等于头尾相加/2,然后求中间

值,然后把求出的中间值的下标的元素跟头下标的元素进行交换,这时候头就是我们的基准值了

找出中间值下标

代码实现:

    public static void quick(int[] array, int start, int end) {
        //如果大于等于,说明找完了
        if (start >= end) {
            return;
        }

        //优化
        if (end - start + 1 <= 15) {
            //使用直接插入排序
            insertSort(array, start, end);
        }

        //优化,三数求中法
        int mid = middle(array, start, end);
        //找出中间值下标和头下标的元素进行交换
        swap(array, start, mid);

        //找出基准值
        int div = quickNeedle(array, start, end);
        quick(array, start, div - 1);
        quick(array, div + 1, end);
    }

    //方法的重载
    public static void insertSort(int[] array, int left, int right) {
        for (int i = left + 1; i <= right; i++) {
            int temp = array[i];
            int j = i - 1;
            for (; j >= left; j--) {
                //这里加不加等号 和稳定有关系
                if (temp < array[j]) {
                    array[j + 1] = array[j];
                } else {
                    //array[j + 1] = temp;
                    break;
                }
            }
            array[j + 1] = temp;
        }
    }

    //找出中间值的下标
    public static int middle(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 {
            //array[left] > array[right]
            if (array[mid] < array[right]) {
                return right;
            } else if (array[mid] > array[left]) {
                return left;
            } else {
                return mid;
            }
        }
    }


快速排序非递归

思路:需要用到栈,首先设置头和尾的下标,然后找基准值调用Hoare法或者挖坑法都行,然后判

断左边元素有几个,如果基准值下标-1大于我们的头下标,就push进栈要push头下标和基准值下

标,如果相等说明左边就一个元素,然后判断右边也是一个道理如果基准值下标+1小于我们的尾

下标,就push进栈要push基准值下标和尾下标,然后while循环判断我们的栈空不空,不空就出右

边下标和左边下标,然后找基准值再调用我Hoare法或者挖坑法,然后再次判断左右元素有几个,

以此为循环

代码实现:

    //快速排序非递归
    public static void quickSort2(int[] array) {
        int start = 0;
        int end = array.length - 1;
        Stack<Integer> stack = new Stack<>();
        int div = partitionHoare(array, start, end);
        if (div - 1 > start) {
            stack.push(start);
            stack.push(div - 1);
        }
        if (div + 1 < end) {
            stack.push(div + 1);
            stack.push(end);
        }
        //栈不为空,弹出两个下标
        while (!stack.isEmpty()) {
            end = stack.pop();
            start = stack.pop();
            //接着整理
            div = partitionHoare(array, start, end);
            if (div - 1 > start) {
                stack.push(start);
                stack.push(div - 1);
            }
            if (div + 1 < end) {
                stack.push(div + 1);
                stack.push(end);
            }
        }
    }

快速排序总结:

1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)

4. 稳定性:不稳定


归并排序

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若

将两个有序表合并成一个有序表,称为二路归并

图解

分解思路:先设置头和尾,然后找出中间下标,然后递归左边以头和中间下标开始递归,右边以中

间下标+1和尾开始递归,当递归到头和尾下标一样,走到一起了开始返回,计算出mid后,传入第

一个式子的end就是mid,然后递归,mid更新,以此类推

怎么递?怎么归?怎么合并?

递归到只有单个元素的时候归,然后合并,合并完归到上一个式子的(mid+1,end)方法接着分

解到只有单个元素,然后合并以此类推

合并思路:写一个方法,记录刚才分解的元素的下标,也可以不记录,记录下来好理解一点,然后创建一个数组,长度是最右边下标-最左边下标+1,然后开始合并

代码实现:

    //归并排序
    public static void mergeSort(int[] array) {
        mergeSort(array, 0, array.length - 1);
    }

    private static void mergeSort(int[] array, int start, int end) {
        if (start >= end) {
            return;
        }
        //递归分解
        int mid = (start + end) / 2;
        mergeSort(array, start, mid);
        mergeSort(array, mid + 1, end);
        //合并
        merge(array, start, mid, end);
    }

    //合并
    private static void merge(int[] array, int left, int mid, int right) {
        //这些都可以不定义,方便理解
        int s1 = left;
        int e1 = mid;
        int s2 = mid + 1;
        int e2 = right;

        //创建一个新的数组
        int[] tmpArr = new int[right - left + 1];
        //从0下标开始存
        int k = 0;
        while (s1 <= e1 && s2 <= e2) {
            //比较元素大小
            if (array[s1] <= array[s2]) {
                tmpArr[k++] = array[s1++];
            } else {
                tmpArr[k++] = array[s2++];
            }
        }

        //走到这 说明还有数据没存完
        while (s1 <= e1) {
            tmpArr[k++] = array[s1++];
        }
        while (s2 <= e2) {
            tmpArr[k++] = array[s2++];
        }

        //拷贝给原来的数组
        for (int i = 0; i < tmpArr.length; i++) {
            //为什么+left? 不然右边也是从0下标拷贝 会覆盖掉原来的
            array[i + left] = tmpArr[i];
        }
    }


归并排序非递归

思路:先从1个开始调整有序,然后2个,然后4个,然后8个,但其实1个就是有序的

设置变量gap从1开始,代表每组几个数据,就像上面说的从1个开始逐渐到8个

设置for循环i从0下标开始,每次递增i+=gap*2,表示每次调整数据每一组2个,随着gap的增加,

每组4个,然后每组8个,就是每次分2个一组,然后合并成有序的,然后2个2个都合并并且有序

了,然后gap增加,然后每组4个4个合并并且有序,以此类推

注意:如果是偶数个这样写没什么问题,但是如果奇数个这样写,mid和right可能会越界,所以当

mid和right越界的时候,把它调整到数组长度-1的下标,然后调整合并

代码实现:

    //归并排序非递归
    public static void mergeSortNor(int[] array) {
        //每组(gap)几个数组
        int gap = 1;
        while (gap < array.length) {
            for (int i = 0; i < array.length; i += gap * 2) {
                int left = i;
                int mid = left + gap - 1;
                int right = mid + gap;

                //越界问题
                if (mid >= array.length) {
                    mid = array.length - 1;
                }
                if (right >= array.length) {
                    right = array.length - 1;
                }

                //合并
                merge(array, left, mid, right);
            }
            gap *= 2;
        }
    }

归并排序总结:

1. 归并的缺点在于需要O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(N)

4. 稳定性:稳定


排序算法复杂度及稳定性分析


计数排序

不完全思路:比如0-9的数字乱序给它进行排序,创建一个数字,下标从0-9,这个数组也可以叫计

数数组,遍历0-9的数字,遍历到0,计数数0下标+1,还是0继续+1,此时0下标对应的就是2,代

表有2个,没有出现的话就标记0,以此类推,遍历完后,然后输出就变成有序的了

修改思路:但是这是0-9的数字,所以不行,得考虑大的数字,所以要设置一个最大最小值,通过

遍历array数值得出最大最小值,然后count数组的长度是大小值相减+1,然后遍历array数组,

count[array[i]-minval]++,通过这样对出现的数据,在count数组的i下标进行计数,然后还要重写 写

回到原来的数组,for遍历count数组,然后while循环判断count数组下标存的数字的次数是不是大于

0,大于0才有,小于等于都是没有的,然后还要设置一个index=0,array从0下标开始存,array[index]=i+minval,然后下标++,count[i]- -,count数组下标的次数--

代码实现:

   //计数排序 不用比较大小进行排序
    public static void countSort(int[] array) {
        int minVal = array[0];
        int maxVal = array[0];
        //获取array数组中的最大和最小值
        for (int i = 1; i < array.length; i++) {
            if (array[i] < minVal) {
                minVal = array[i];
            }
            if (array[i] > maxVal) {
                maxVal = array[i];
            }
        }

        //确定计数数组长度
        int len = maxVal - minVal + 1;
        int[] count = new int[len];

        //遍历array数组  array数组元素出现的次数存放到计数数组存放
        for (int i = 0; i < array.length; i++) {
            //array数组的元素-最小值
            //一开始count数组的每个下标存放的都是0
            count[array[i] - minVal]++;
        }
        int index = 0;
        for (int i = 0; i < count.length; i++) {
            //count数组i下标的元素要大于0
            while (count[i] > 0) {
                //重写 写回array数组 从0下标开始
                array[index] = i + minVal;
                index++;
                count[i]--;
            }
        }
    }

以上便是基本的排序算法,欢迎阅读

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【论文阅读】Masked Autoencoders Are Scalable Vision Learners

Masked Autoencoders Are Scalable Vision Learners 引用&#xff1a; He K, Chen X, Xie S, et al. Masked autoencoders are scalable vision learners[C]//Proceedings of the IEEE/CVF conference on computer vision and pattern recognition. 2022: 16000-16009. 论文链…

wireshark抓tcp包使用指南

本博文源于笔者不断探索加上去网络总结获得的经验&#xff0c;撰写wireshark如何抓tcp包 文章目录 1、打开wireshark2、选择网络源3、搜索ip地址与tcp条件4、看灰色的条纹 1、打开wireshark 2、选择网络源 选择自己当前的ip地址适用于的网络源&#xff0c;比如这里选择“以太…

ETH Gas 之 Base Fee Priority Fee

前情回顾 ETH网络 之 Gas EIP-1559 EIP-1559 EIP-1559是以太坊改进提案&#xff08;Ethereum Improvement Proposal&#xff09;&#xff0c;旨在改进以太坊的交易费用机制。该提案引入了一种新的交易费用模型&#xff0c;以提高交易费用的可预测性和网络的效率。我们本文各…

故障诊断 | 一文解决,GRNN广义回归神经网络的故障诊断(Matlab)

文章目录 效果一览文章概述专栏介绍模型描述源码设计参考资料效果一览 文章概述 故障诊断 | 一文解决,GRNN广义回归神经网络的故障诊断(Matlab) 专栏介绍

拥抱DevOps,开启数字化转型的加速器

在数字化浪潮席卷全球的今天&#xff0c;企业面临着前所未有的挑战与机遇。为了保持竞争力并适应快速变化的市场需求&#xff0c;数字化转型已成为企业发展的必由之路。而在这一过程中&#xff0c;DevOps作为一种全新的开发与运维理念&#xff0c;正逐渐成为推动企业数字化转型…

数据库设计三大范式

第一范式 确保每列保持原子性 即数据库表中的所有字段值都是不可分解的原子值 如果地址这个字段频繁访问&#xff0c; 则将地址这个属性重新划分为 省份 城市&#xff0c;详细地址等部分进行存储&#xff0c;这样才算是满足数据库的第一范式 第二范式 确保表中的每列都和主…

Python基础入门 --- 6.数据容器

文章目录 Python基础入门第六章&#xff1a;6.数据容器6.1 列表6.1.1 列表下标索引6.1.2 列表常用操作查找指定某元素的下标修改指定位置的元素值插入元素追加元素方式1追加元素方式2删除元素删除某元素在列表中的第一个匹配项清空列表统计某元素在列表中的数量统计列表元素个数…

vue+elementUI实现树形穿梭框

1.实现效果 2.整体思路 将左侧选中的节点移动到右侧&#xff0c;还要保持树结构&#xff0c;意味着移动子节点&#xff0c;需要把该子节点对应的父节点甚至父节点的父节点一并移到右侧形成一个新的树结构&#xff0c;树结构的层级和原来的树保持一致&#xff0c;只是右侧展示…

全国媒体公关服务资源分析,媒体邀约资源包括哪些?-51媒体网

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 全国媒体公关服务资源分析是一个涵盖多方面的复杂议题&#xff0c;主要涉及到不同媒体类型、传播渠道、以及公关策略等多个维度。在当前媒体环境下&#xff0c;媒体公关服务资源主要包括…

机器人路径规划:基于斑翠鸟优化算法(Pied Kingfisher Optimizer ,PKO)的机器人路径规划(提供MATLAB代码)

一、机器人路径规划介绍 移动机器人&#xff08;Mobile robot&#xff0c;MR&#xff09;的路径规划是 移动机器人研究的重要分支之&#xff0c;是对其进行控制的基础。根据环境信息的已知程度不同&#xff0c;路径规划分为基于环境信息已知的全局路径规划和基于环境信息未知或…

【论文阅读】通过组件对齐评估和改进 text-to-SQL 的组合泛化

Measuring and Improving Compositional Generalization in Text-to-SQL via Component Alignment NAACL 2022| CCF B Abstract 在 text-to-SQL 任务中&#xff0c;正如在许多 NLP 中一样&#xff0c;组合泛化是一个重大挑战&#xff1a;神经网络在训练和测试分布不同的情况…

Python 深度学习第二版(GPT 重译)(二)

四、入门神经网络&#xff1a;分类和回归 本章涵盖 您的第一个真实世界机器学习工作流示例 处理矢量数据上的分类问题 处理矢量数据上的连续回归问题 本章旨在帮助您开始使用神经网络解决实际问题。您将巩固从第二章和第三章中获得的知识&#xff0c;并将所学应用于三个新…

数据之王国:解析Facebook的大数据应用

引言 作为全球最大的社交媒体平台之一&#xff0c;Facebook拥有庞大的用户群体和海量的数据资源。这些数据不仅包括用户的个人信息和社交行为&#xff0c;还涵盖了广告点击、浏览记录等多方面内容。Facebook通过巧妙地利用这些数据&#xff0c;构建了强大的大数据应用系统&…

T470 双电池机制

ThinkPad系列电脑牛黑科技双电池管理体系技术,你知道吗&#xff1f; - 北京正方康特联想电脑代理商 上文的地址 在放电情况下&#xff1a;优先让外置电池放电&#xff0c;当放到一定电量后开始让内置电池放电。 在充电情况下&#xff1a;优先给内置电池充电&#xff0c;当充…

uboot - pinctrl - FPGA回片前测试阶段 - 设置GPIO引脚复用失败

问题描述 pinctrl设置引脚复用失败&#xff0c;没有调用到controller中的set_groups_function函数。 问题定位 pinctrl如何注册dm节点如何进行设备树中各个设备节点下的复用配置为什么没调用到控制器实现的set_groups_function函数 &gpio0 {status "okay";p…

web自动化3-pytest前后夹具

一、pytest前后置&#xff08;夹具&#xff09;-fixture 夹具的作用&#xff1a;在用例执行之前和之后&#xff0c;需要做的准备工作之前和收尾工作。 用于固定测试环境&#xff0c;以及清理回收资源。 举个例子&#xff1a;访问一个被测页面-登录页面&#xff0c;执行测试用…

阿里云镜像仓库服务--推送docker image到远程仓库

一、背景 阿里云对于镜像仓库服务的使用文档已比较完善&#xff0c;结合它给的示例。 本文是站在小白用户的视角&#xff0c;梳理整个的使用过程以及遇到的问题。 二、使用步骤 阿里云镜像仓库服务和harbor、nexus等私有仓库等并没有什么大差不差之处&#xff0c;仍旧是四步走…

Java设计模式 | 工厂方法模式

工厂方法模式 针对简单工厂模式案例中的缺点&#xff0c;使用工厂方法模式就可以完美的解决&#xff0c;完全遵循开闭原则。简单工厂模式只有一个工厂类&#xff0c;负责创建所有产品&#xff0c;如果要添加新的产品&#xff0c;就需要修改工厂类的代码。而工厂方法模式引入了…

鸿蒙Harmony应用开发—ArkTS-转场动画(组件内隐式共享元素转场)

geometryTransition用于组件内隐式共享元素转场&#xff0c;在组件显示切换过程中提供平滑过渡效果。通用transition机制提供了opacity、scale等转场动效&#xff0c;geometryTransition通过id绑定in/out组件(in指入场组件、out指出场组件)&#xff0c;使得组件原本独立的trans…

IOS/Android App备案(uniapp)

IOS/App备案 IOS备案Android备案 IOS备案 准备好p12证书即可 链接: https://aitoolnav.caichuangkeji.com/#/AppMd5 Android备案 上DCLOUD开发者中心&#xff0c;找到相关应用后&#xff0c;直接查看证书即可获取到MD5 公钥&#xff1a;先根据上述页面下载证书&#xff0c;…