常见8大排序算法详解

news2024/9/22 23:36:44

常见8大排序算法

分别是冒泡排序、选择排序、插入排序、希尔排序、快速排序、堆排序、归并排序、基数排序(桶排序)

冒泡排序

思路

n个数字从小到大排序,每个数和它后面的数比较,小的放前面,大的放后面,依次执行,这样一轮下来就能将一个最大的放到最后。执行n-1轮就能全部排序完。

代码

/**
 * @author 康有为
 * 冒泡排序
 */
public class BubbleSort {
    public void bubbleSort(int[] arr){
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1; j++) {
                if (arr[j] > arr[j+1]){
                    int index = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = index;
                }
            }
        }
    }
}

选择排序

思路

n个数字从小到大排序,每轮选择一个最小的放到最前面,执行n-1轮 

代码

package 排序;

/**
 * @author 康有为
 * 选择排序
 */
public class SelectSort {
    public void selectSort(int[] arr){
        for (int i = 0; i < arr.length - 1; i++) {
            int min = i;
            //找出一个最小的
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[min]){
                    min = j;
                }
            }
            //与第一个交换
            int index = arr[i];
            arr[i] = arr[min];
            arr[min] = index;
        }
    }
}

插入排序

思路

        类似打斗地主时,摸一张插入到手里排序,再摸一张插入到手里排序。

        n个数字从小到大排序,将数字分成未排序的和已排序的两部分,每次 从未排序的中拿出一个,放入到已排序中进行排序:如果比前面的大,那直接结束,如果比前面的小,就与之交换位置,再与前面的交换,一直到头,一轮结束。

代码

/**
 * @author 康有为
 * 插入排序
 */
public class InsertSort {
    public void insertSort(int[] arr){
        for (int i = 1; i < arr.length; i++) {
            for (int j = i; j > 0; j--) {
                if (arr[j] < arr[j - 1]){
                    int index = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = index;
                }else {
                    break;
                }
            }
        }
    }
}

希尔排序

思路

视频讲解:王道计算机考研 数据结构8.2_2_希尔排序_哔哩哔哩_bilibili

        希尔排序是在插入排序的基础上进行改进,所以请先理解好插入排序,再来看希尔排序。简单插入排序是对一组数据进行插入排序,而希尔排序是现将数组分成几个组,让其在小组里面排序,一开始分成 len/2个小组,排序完毕后,再分成len/2/2个小组,一直到分成1个小组,执行简单插入排序。

代码

/**
 * 希尔排序
 *
 * @author 康有为
 * @date 2023/04/25
 */
public class ShellSort {
    public void shellSort(int[] arr) {
        int gap = arr.length / 2;
        //while循环来改变gap,每次除2
        while (gap >= 1) {
            //遍历每个元素,将其在其所在的组里进行简单插入排序
            for (int i = 0; i < arr.length; i++) {
                for (int j = i; j >= gap; j -= gap) {
                    if (arr[j] < arr[j - gap]) {
                        int index = arr[j];
                        arr[j] = arr[j - gap];
                        arr[j - gap] = index;
                    } else {
                        break;
                    }
                }

            }
            gap = gap / 2;
        }
    }
}

快速排序

思路

视频讲解:王道计算机考研 数据结构8.3_2_快速排序_哔哩哔哩_bilibili

核心思路

        在数组中选一个基准值,扫描其余数字,小的放到基准值左边,大的放到基准值右边。然后再对基准值左右两边进行递归。

算法描述

        左指针从左往右遍历,找到左边得到内奸(即 不是小于基准值的数),右指针从右往左边里,找到右边的内奸(即 不是大于基准值的数),两者都有内奸的内时候,互换内奸。两指针相遇且都指向基准值的时候,结束。然后再对基准值左右两边进行递归。

代码


/**
 * 快速排序
 *
 * @author 康有为
 * @date 2023/04/25
 */
public class QuickSort {
    public void quickSort(int[] arr){
        quickSort(arr,0,arr.length - 1);
    }
    public void quickSort(int[] arr,int start,int end){
        if (start >= end){
            return;
        }
        int left = start;
        int right = end;
        int mid = (left + right) / 2;
        //三个指针重合就结束
        while (!(mid == left && left == right)){
            if (arr[left] < arr[mid]){
                left++;
            }
            if (arr[right] > arr[mid]){
                right --;
            }
            //三个指针重合就结束
            if (left == right && right == mid){
                break;
            }
            //两支针所指都不符合自己要求,就互换
            if (arr[left] >= arr[mid] && arr[right] <= arr[mid]){
                int index = arr[left];
                arr[left] = arr[right];
                arr[right] = index;
            }
        }

        if (start < mid){
            //向左递归
            quickSort(arr,start,mid);
        }
        if (mid > end){
            //向右递归
            quickSort(arr,mid,end);
        }


    }
}

堆排序

思路

视频讲解:排序算法:堆排序【图解+代码】_哔哩哔哩_bilibili

步骤就是两步:1.构建大顶堆 2.进行堆排序

1.构建大顶堆

什么是大顶堆?

下图就是一个大顶堆

大顶堆要求:每个根节点都要比两个子节点大。(小顶堆同理,每个根节点要比两个子节点小)

使用数组来存储大顶堆

规律

下标为i的节点的父节点下标::( i - 1 ) / 2【整数除法】

下标为i的节点的左孩子下标:i * 2 + 1

下标为i的节点的右孩子下标:i * 2 + 2

怎么维护一个大顶堆?

参数:

  1. 数组
  2. 要维护的父节点的小标

步骤

  1. 找到父节点的两个孩子节点
  2. 将大的那个孩子节点与父节点交换
  3. 交换之后,对交换的那个子节点,进行递归维护,因为刚刚的维护,原本子节点也是大顶堆,交换之后可能破坏了

代码

/**
 * heapify
 * 维护大顶堆
 *
 * @param arr        数组
 * @param parentNode 要维护的父节点的下标
 * @param len        大顶堆的长度
 */
public void heapify(int[] arr, int parentNode, int len){
    int lSon = parentNode * 2 + 1;
    int rSon = parentNode * 2 + 2;
    //左孩子节点 如果 大,那就交换位置
    if (lSon < len && arr[lSon] > arr[parentNode]){
        swap(arr,lSon,parentNode);
        //交换完毕后再对左孩子节点进行递归维护
        heapify(arr,lSon,len);
    }
    //右孩子节点 如果 大,那就交换位置
    if (rSon < len && arr[rSon] > arr[parentNode]){
        swap(arr,rSon,parentNode);
        //交换完毕后再对右孩子节点进行递归维护
        heapify(arr,rSon,len);
    }
}

/**
 * 数组元素交换
 */
void swap(int[] arr,int a, int b){
    int index = arr[a];
    arr[a] = arr[b];
    arr[b] = index;
}

构建大顶堆也就是将一个无序的堆维护成大顶堆

维护的顺序是从最后一个父节点开始,从后往前维护

 例如下面的大顶堆

 那么我们就得从最后一个4开始维护,维护完4这个父节点,再维护1这个节点。

因为 下标为i的节点的父节点下标::( i - 1 ) / 2【整数除法】,所以我们开始遍历的维护大顶堆

2.进行堆排序

思路

        将无序的数组排成大顶堆,这样首元素就是最大的,然后将其放到最后,大顶堆长度减1,再维护大顶堆,重复操作

        类似选择排序,选择排序是将最小的元素放到前面,堆排序是通过大顶堆,将最大的元素放到后面

         也就是将最后一个元素和 大顶堆堆顶的元素交换位置,并将最后一个元素从大顶堆中删除,也就是让大顶堆的长度减1,再维护以下这个大顶堆即可

void heapSort(int[] arr){
    int len = arr.length;
    //1.建立大顶堆:从最后一个父节点开始向前遍历维护大顶堆
    for (int i = (len-1-1)/2; i >= 0 ; i--) {
        heapify(arr,i,len);
    }
    //2.开始排序:将最后一个元素与大顶堆堆顶元素交换,然后大顶堆长度减1
    for (int i = len-1; i > 0; i--) {
        swap(arr,i,0);
        heapify(arr,0,i);
    }
}

代码

package 排序;

/**
 * 堆排序
 *
 * @author 康有为
 * @date 2023/04/26
 */
public class HeapSort {
    public void heapSort(int[] arr){
        //1.建立大顶堆:需要从后往前的遍历每个父节点,对父节点进行维护
        int len = arr.length;
        for (int i = (len-2)/2; i >= 0 ; i--) {
            heapify(arr,i,len);
        }

        //2.开始排序
        for (int i = 0; i < len ; i++) {
            swap(arr,0,len-1);
            len--;
            heapify(arr,0,len);
        }
    }


    /**
     * heapify
     * 维护大顶堆
     *
     * @param arr        数组
     * @param parentNode 要维护的父节点的下标
     * @param len        维护数组的长度
     */
     void heapify(int[] arr, int parentNode, int len){
        int lSon = parentNode * 2 + 1;
        int rSon = parentNode * 2 + 2;
        //左孩子节点 如果 大,那就交换位置
        if (lSon < len && arr[lSon] > arr[parentNode]){
            swap(arr,lSon,parentNode);
            //交换完毕后再对左孩子节点进行递归维护
            heapify(arr,lSon,len);
        }
        //右孩子节点 如果 大,那就交换位置
        if (rSon < len && arr[rSon] > arr[parentNode]){
            swap(arr,rSon,parentNode);
            //交换完毕后再对右孩子节点进行递归维护
            heapify(arr,rSon,len);
        }
    }

    /**
     * 交换
     */
    void swap(int[] arr, int a ,int b){
        int index = arr[a];
        arr[a] = arr[b];
        arr[b] = index;
    }

}

归并排序

思路

视频讲解:8.5_1_归并排序_哔哩哔哩_bilibili

        先写出 将两个分别有序部门合并成一个整体有序的 代码:merge

        然后递归对每部分进行合并

1.合并两个有序部分

找一个辅助数组,从两个有序数组中分别取出小的,放到里面,最后就是有序的。


    /**
     * 合并
     * 合并数组中 两个 有序的连续片段
     * 也就是将左边有序的部分 和 右边有序的部分 合并成一个大的有序部分
     *
     * @param arr    数组
     * @param left   左
     * @param middle 中间
     * @param right  右
     * @param temp   临时数组
     */
    void merge(int [] arr,int left,int middle,int right,int []temp){

          int i = left; // 初始化i, 左边有序序列的初始索引
          int j = middle + 1; //初始化j, 右边有序序列的初始索引
          int t = 0; // 指向temp数组的当前索引

          //先把左右两边(有序)的数据按照规则填充到temp数组
          //直到左右两边的有序序列,有一边处理完毕为止
          while (i <= middle && j <= right) {//继续
              //如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
              //即将左边的当前元素,填充到 temp数组
              //然后 t++, i++
              if(arr[i] <= arr[j]){
                  temp[t] = arr[i];
                  t++;
                  i++;
              }else { //反之,将右边有序序列的当前元素,填充到temp数组
                  temp[t] = arr[j];
                  t++;
                  j++;
              }
          }

          //把有剩余数据的一边的数据依次全部填充到temp
          //左边的有序序列还有剩余的元素,就全部填充到temp
          while (i <= middle){
              temp[t] = arr[i];
              t++;
              i++;
          }

          //右边的有序序列还有剩余的元素,就全部填充到temp
          while (j <= right){
              temp[t] = arr[j];
              t++;
              j++;
          }

          //将temp数组的元素拷贝到arr
          //注意,并不是每次都拷贝所有
          t = 0;
          int tempLeft = left; //
          while (tempLeft <= right){
              arr[tempLeft] = temp[t];
              t++;
              tempLeft++;
          }

    }

2.递归将数组分成两份,进行合并

一直除2 来分成两部分,直到分成一个数,这时候,一个数是有序的,再回退就是两个数,将两个数合并,再往上。。。。。。

    void sortEntrance(int [] arr,int left, int right,int []temp){

        if (left < right){
            int mid = (left+right)/2;
            //向左递归
            sortEntrance(arr,left,mid,temp);
            //向右递归
            sortEntrance(arr,mid+1,right,temp);
            //归并
            merge(arr,left,mid,right,temp);
        }

    }

代码

package 排序;

import java.util.Arrays;

/**
 * 归并排序
 *
 * @author 康有为
 * @date 2023/04/28
 */
public class MergeSort {

    public void mergeSort(int []arr){
        int [] temp = arr.clone();
        sortEntrance(arr,0,arr.length-1,temp);
    }

    void sortEntrance(int [] arr,int left, int right,int []temp){

        if (left < right){
            int mid = (left+right)/2;
            //向左递归
            sortEntrance(arr,left,mid,temp);
            //向右递归
            sortEntrance(arr,mid+1,right,temp);
            //归并
            merge(arr,left,mid,right,temp);
        }

    }

    /**
     * 合并
     * 合并数组中 两个 有序的连续片段
     * 也就是将左边有序的部分 和 右边有序的部分 合并成一个大的有序部分
     *
     * @param arr    数组
     * @param left   左
     * @param middle 中间
     * @param right  右
     * @param temp   临时数组
     */
    void merge(int [] arr,int left,int middle,int right,int []temp){

          int i = left; // 初始化i, 左边有序序列的初始索引
          int j = middle + 1; //初始化j, 右边有序序列的初始索引
          int t = 0; // 指向temp数组的当前索引

          //先把左右两边(有序)的数据按照规则填充到temp数组
          //直到左右两边的有序序列,有一边处理完毕为止
          while (i <= middle && j <= right) {//继续
              //如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
              //即将左边的当前元素,填充到 temp数组
              //然后 t++, i++
              if(arr[i] <= arr[j]){
                  temp[t] = arr[i];
                  t++;
                  i++;
              }else { //反之,将右边有序序列的当前元素,填充到temp数组
                  temp[t] = arr[j];
                  t++;
                  j++;
              }
          }

          //把有剩余数据的一边的数据依次全部填充到temp
          //左边的有序序列还有剩余的元素,就全部填充到temp
          while (i <= middle){
              temp[t] = arr[i];
              t++;
              i++;
          }

          //右边的有序序列还有剩余的元素,就全部填充到temp
          while (j <= right){
              temp[t] = arr[j];
              t++;
              j++;
          }

          //将temp数组的元素拷贝到arr
          //注意,并不是每次都拷贝所有
          t = 0;
          int tempLeft = left; //
          while (tempLeft <= right){
              arr[tempLeft] = temp[t];
              t++;
              tempLeft++;
          }

    }
}

基数排序(桶排序)

思路

视频讲解:8.5_2_基数排序_哔哩哔哩_bilibili

之前的排序都是每次直接比较元素的大小,而基数排序不是。

  1. 将所有带比较数值统一为同样的数位长度,数据较短的数前面补0。
  2. 定义10个“桶子”,依次是0-9。
  3. 将待排序数组的元素的最低位 对应放到桶子里面,然后再收集起来。
  4. 在将待排序数组的元素的下一位 对应放到桶子里面,再收集。
  5. 循环到最高位,收集起来就排序好了。

总的来说就是将元素 按照它的从最低位放到对应的桶里面、收集起来,这样从最低位一直到最高位也放到桶里面,收集完毕,数组就有序了。

如果要从小到大排序,就从0号桶开始收集,如果要从大到小排序,就从10号桶排序

代码

package 排序;

/**
 * 基数排序
 *
 * @author 康有为
 * @date 2023/05/04
 */
public class RadixSort {

    public void radixSort(int []arr){
        int arrLen = arr.length;
        //找出数组最大的元素
        int max = arr[0];
        for (int i = 1; i < arrLen; i++) {
            if (arr[i] > max){
                max = arr[i];
            }
        }

        //统计最大元素的长度
        int maxLen = 1;
        int index = 1;
        while (true){
            index = index * 10;
            if (Math.abs(max) >= index){
                maxLen ++;
            }else {
                break;
            }

        }



        //将数组元素的 某一位 放到桶里面,位数从末位到首位
        //如何拿到元素的 每一位?例如数字321,321 % 10 /1 = 1,321 % 100 /10 = 2,321 % 1000 /100 = 3
        //从最低位 遍历 到最高位
        for (int i = 1; i <= maxLen; i++) {
            //定义桶
            int[][] barrel = new int[10][arrLen];
            //为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数
            int[] barrelNum = new int[10];
            //将元素放到桶里面
            for (int j = 0; j < arrLen; j++) {
                //拿到数组的某一位
                int num =(int) (arr[j] % Math.pow(10,i) /Math.pow(10,i-1));
                //将数组的元素按照某一位放置到 对应的桶里面
                barrel[num][barrelNum[num]] = arr[j];
                barrelNum[num]++;
            }
            //从每个桶里取出元素
            index = 0;
            for (int j = 0; j < 10; j++) {
                //只有桶里面有数据才取出
                if (barrelNum[j] != 0){
                    for (int k = 0; k < barrelNum[j]; k++) {
                        arr[index] = barrel[j][k];
                        index++;
                    }
                }

            }

        }
    }
}

负数的问题

负数不能排序,要排序负数

桶排序对于负数的处理_桶排序可以排负数吗_macro_buaa的博客-CSDN博客

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

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

相关文章

微信小程序学习实录5(H5嵌入小程序、map组件、地图调起功能、腾讯百度高德导航页、返回web-view页)

H5嵌入微信小程序 一、H5页面地图1.H5地图加载2.标注事件 二、H5返回微信小程序1.H5页面核心代码2.微信小程序接收传参核心代码 三、开发中遇见的坑1.wx.openLocation调起地图后需要点击两次返回才到web-view页面2.H5无法调用百度定位new BMap.Geolocation对象3.安卓某些机型无…

Linux:《tar》归档命令

准备好4个文件然后使用tar命令进行归档 最常用的是 -c, --create&#xff08;小写&#xff09; 建立新的存档 -f, --file [HOSTNAME:]F 指定存档或设备 (缺省为 /dev/rmt0) -z, --gzip, --ungzip 用 gzip 对存档压缩或解压 -j&…

京东数据分析:2023年Q1白酒电商整体动销增长,中低端酒企压力大

早在年初就有白酒市场业内人士表示&#xff0c;2023年春节白酒消费市场整体景气度较高&#xff0c;白酒动销表现较为优秀&#xff0c;预计2023年一季度白酒动销有望实现一定的增长。 对于这一观点&#xff0c;我们在今年电商数据平台鲸参谋出炉的Q1白酒销售数据表现中得到了验证…

【软考高级】2019年系统分析师案例分析

1、阅读以下关于软件系统分析的叙述&#xff0c;在答题纸上回答问题1至问题3。 【说明】 某软件企业为电信公司开发一套网上营业厅系统&#xff0c;以提升服务的质量和效率。项目组经过分析&#xff0c;列出了项目开发过程中的主要任务、持续时间和所依赖的前置任务&#xff…

1.0 Vue的编译和运行

1、编程范式&#xff1a;命令式和声明式 编程范式是指一种程序语言的代码风格、样式&#xff0c;每一种范式都包含了代码特征和结构&#xff0c;以及处理错误的方式。 例如现在需要实现生成一个div模块&#xff0c;其显示的文本内容为hello world&#xff0c;添加一个点击事件…

X3派caffe yolov3 部署demo

yolov3放置在docker中/open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/04_detection/02_yolov3_darknet53/mapper 模型所需要的prototxt和caffe模型yolov3.caffemodel文件放置在docker中的/open_explorer/ddk/samples/ai_toolchain/model_zoo/mapper/de…

78页2023年智慧公安发展构思与建设解决方案(ppt可编辑)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除。 总体架构10 建设方案-网络系统11 物联网15 视频网系统16 视频专网主干网根据运营商链路分为若干个环网部署&#xff0c;市局两台核心交换机位于网络核心层&#xff1b;部分…

SpringCloud 分布式事务组件之Seata

目录 背景介绍什么是分布式事务什么叫做逆向补偿呢互联网最流行的分布式事务组件seata总结 背景 大家好&#xff0c;今天给大家分享一个在2022年出去面试Java几乎必问的一个技术&#xff0c;那就是seata。什么&#xff1f;&#xff1f;你才看了第一句话心里有闪现了无数个问…

024 - C++ 虚函数

本期我们学习的是 C 中的虚函数。 过去的几期&#xff0c;我们一直在讨论类、面向对象编程、继承这些内容&#xff0c;所有的这些内容&#xff0c;包括本期我们将要学习的虚函数&#xff0c;对整个面向对象的概念都非常重要。 虚函数能干什么呢? 虚函数允许我们在子类中重写…

关于C语言的一些笔记

文章目录 May4,2023常量问题基本数据类型补码printf的字符格式控制关于异或、异或的理解赋值运算i和i的区别关系运算符 摘自加工于C技能树 May4,2023 常量问题 //定义常量 const float PI; PI 3.14; //false ,这种声明变量是错误的&#xff0c;常量声明之后就不能修改&…

树脂塞孔有哪些优缺点及应用?

树脂塞孔的概述 树脂塞孔就是利用导电或者非导电树脂&#xff0c;通过印刷&#xff0c;利用一切可能的方式&#xff0c;在机械通孔、机械盲埋孔等各种类型的孔内进行填充&#xff0c;实现塞孔的目的。 树脂塞孔的目的 1 树脂填充各种盲埋孔之后&#xff0c;利于层压的真空下…

关于使用Notion的board做工作安排这件事

关于使用Notion的board做工作安排这件事 Created: May 4, 2023 5:39 PM 壹 最近想用一个工具来实现平时工作的记录、跟踪、留痕以及年终的统计&#xff0c;之前尝试过幕布、微软的todo、手机自带的备忘录等工具&#xff0c;但是还是不能够完全满足需求。之前也用过一段时间的…

SPSS如何进行回归分析之案例实训?

文章目录 0.引言1.线性回归分析2.曲线回归分析3.非线性回归分析4.Logistic回归分析5.有序回归分析6.概率回归分析7.加权回归分析 0.引言 因科研等多场景需要进行绘图处理&#xff0c;笔者对SPSS进行了学习&#xff0c;本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上…

Redis 实战篇:巧用 Bitmap 实现亿级海量数据统计

目录 二值状态统计判断用户登陆态SETBIT 命令GETBIT 命令第一步&#xff0c;执行以下指令&#xff0c;表示用户已登录。第二步&#xff0c;检查该用户是否登陆&#xff0c;返回值 1 表示已登录。第三步&#xff0c;登出&#xff0c;将 offset 对应的 value 设置成 0。 用户每个…

【web】HTTP工作原理及应用

一、浏览器工作 浏览器输入网址后&#xff0c;从DNS服务器中查找对应的IP&#xff0c;并返回客户端浏览器&#xff0c;然后通过ip地址去访问服务器。&#xff08;操作系统中host文件存了一些对应的IP地址&#xff0c;浏览器拿到域名会先从host文件中查找ip&#xff0c;如果找…

重工业生产VR虚拟现实数字化互动展示为后续招商引资打好基础和口碑

智慧工业厂区已经是当今城市规划和发展的重要焦点。华锐视点运用数字孪生&#xff0c;三维虚拟仿真和3D可视化打造的智慧园区管理平台&#xff0c;不仅提升了工业厂区吸引力&#xff0c;而且促进工业厂区可持续发展&#xff0c;给予了园区互联网先进技术发展的基础&#xff0c;…

Noah-MP陆面过程模型建模方法与站点、区域模拟实践技术

查看原文&#xff1a;Noah-MP陆面过程模型建模方法与站点、区域模拟实践技术 目标&#xff1a; 了解陆表过程的主要研究内容以及陆面模型在生态水文研究中的地位和作用&#xff1b;熟悉模型的发展历程&#xff0c;常见模型及各自特点&#xff1b;理解Noah-MP模型的原理&#…

[笔记]Windows使用OpenVpn构建虚拟局域网

文章目录 前言一、Windows Openvpn方案1.1 openvpn server windows端安装目录结构服务端安装复制服务端配置文件修改服务端配置文件配置8080允许通过防火墙启动服务端 1.2 openvpn client windows端安装复制服务端生成的配置文件到客户端的config启动客户端 二、连通测试三、常…

数字孪生可视化平台开发 打通现实与虚拟世界

大数据时代背景下&#xff0c;数字孪生技术被应用到智慧建设中&#xff0c;数字孪生是指在虚拟世界中1:1构建一个与现实世界的物体、场景和其他方面都完全相同的孪生景象。数字孪生可视化平台是一种基于虚拟现实技术的数字化模型&#xff0c;通过将真实世界中的物体或场景数字化…

Ubuntu---mysql出现ERROR1698(28000):Access denied for user root@localhost错误解决方法

查看mysql版本&#xff1a; 安装完成后&#xff0c;登录mysql的时候就出现了如下错误&#xff1a; 因为安装的过程中没让设置密码&#xff0c;可能密码为空&#xff0c;但无论如何都进不去mysql。 下面是处理过程&#xff1a; Step1&#xff1a;修改mysqld.cnf配置文件 在ubun…