6、java中的排序算法

1、简介

排序是将元素按着指定关键字的大小递增或递减进行数据的排列,排序可以提高查找的效率

2、排序算法的分类

排序算法可大致分为四类七种,具体分类如下:

       插入排序:直接插入排序、希尔排序

       交换排序:冒泡排序、快速排序

       选择排序:直接选择排序、堆排序

       归并排序

3、插入排序

算法思想:每次将一个元素按着关键字大小插入到他前面已经排好序的子序列中,重复进行这个操作,直至插入所有数据。

3、1 直接插入排序

算法描述:假设前i个元素构成的子序列是有序的,然后根据关键字大小顺序将第i+1个元素a[i] 添加到已经排好序的子序列中,使得插入a[i]后的序列仍是一个有序序列,这样当元素都插入序列时,则排序完成。

算法实现:

   /*** 直接插入排序* @author chaizepeng*/private static void directInsertSort1(int[] array) {for (int i = 1; i < array.length; i++) {int temp = array[i];//拿到下一个需要插入的数值for (int j = i-1; j >= 0; j--) {//遍历已经排好序的集合//将想要插入的元素和已经排好序的集合中的每一个进行比较if (temp < array[j]) {array[j+1] = array[j];}else {array[j+1] = temp;break;}}}}/*** 直接插入排序* @author chaizepeng*/private static void directInsertSort2(int[] array) {for (int i = 1; i < array.length; i++) {int temp = array[i];//拿到下一个需要插入的数值int j ;for (j = i-1; j >= 0 && temp < array[j]; j--) {//遍历已经排好序的集合//将想要插入的元素和已经排好序的集合中的每一个进行比较array[j+1] = array[j];}array[j+1] = temp;}}

算法分析:

假设一个序列{1,2,3,4,5},使用直接插入排序时,每个个元素需要比较1次,移动两次(现将第i个给temp,再将第temp给第i个)即可,则完成排序总需比较n-1次,移动2(n-1)次,时间复杂度是O(n)

再假设一个序列{5,4,3,2,1},使用直接插入排序时,第i个元素准备插入时,需要比较i-1次,移动2+(i-1)次(前一个元素往后移动一次,第i元素先给temp,然后temp再给第1个元素)也就是i+1次,所以n个元素总共许比较n(n-1)/2次,移动(n-1)(n+4)/2次,所以时间复杂度为O(n^2)

所以插入排序算法的时间复杂度在O(n)到O(n^2)之间,其排序效率与比较次数和元素长度直接相关。

3、2 希尔排序

算法描述:

代码实现:

   /*** 希尔排序* @author chaizepeng*/private static void shellSort1(int[] array) {int len = array.length;int i,j,gap;//步长每次除以2,使用步长来对数组进行分组//步长的直接意思就是,每隔len个元素则为同一组元素,步长在数值上等于组数for (gap = len / 2 ; gap > 0 ; gap /= 2){//因为每次都是除以2,所以当步长越小时,每组中的元素越多,越接近于有序//这里是遍历根据步长分割的每一组for (i = 0 ; i < gap ; i++){//将每组中的元素进行排序,j是在i+gap开始的,因为每隔gap个数便是同一组数据//这是遍历每组中的每一个数据,组内数据进行比较,直接插入排序//i+gap正好是获取到数组中的每一个数据for (j = i + gap ; j < len ; j += gap){if(array[j] < array[j - gap]){int temp = array[j];int k = j - gap;while (k >= 0 && array[k] > temp){array[k + gap] = array[k];k -= gap;}array[k + gap] = temp;}}}}}/*** 希尔排序* @param array*/private  static  void shellSort2(int[] array){int len = array.length;int j , gap;for (gap = len / 2 ; gap > 0 ; gap /= 2){for (j = gap ; j < len ; j++){if (array[j] < array[j - gap]){int temp = array[j];int k = j - gap;while (k >= 0 && array[k] > temp){array[k + gap] = array[k];k -= gap;}array[k + gap] = temp;}}}}/*** 希尔排序* @param array*/private static void shellSort3(int[] array) {int i,j,gap;int len = array.length;for (gap = len / 2 ; gap > 0 ; gap /= 2){for (i = gap ; i < len ; i++){for (j = i - gap ; j>= 0 && array[j] > array[j+gap] ; j -= gap){int temp = array[j];array[j] = array[j+gap];array[j+gap] = temp;}}}}

 算法分析:

因为根据之前对直接插入排序的分析可以知道直接插入排序算法的效率与比较次数和元素长度直接相关,可以看出希尔排序是对直接插入排序算法做了优化,针对的就是比较次数和元素的长度,希尔排序讲究先分组排序,这样就见效了移动的次数,随着元素长度的增加,序列趋于有序,减少了比较的次数,降低了时间复杂度。另外,希尔排序的时间复杂度是O(n*(logn)^2)。

排序算法的稳定性:是对关键字相同的元素排序性能的描述,当两个元素A,B相等,排序之前A在B前边,如果排完排完序之后,A仍然在B前边,则说明排序算法是稳定的。自我感觉分析一个算法稳定还是不稳定是可行的,但是如果说一个算法是稳定还是不稳定的应该不准确吧?对于稳定性而言是不是就是对临界元素的一种处理方式而已呢?不必纠结。

 4、交换排序 

4、1 冒泡排序

算法描述:假设按着升序排序,就是从第一个元素开始比较相邻两个元素的值,如果前边的比后边的大,则交换两个值得位置,然后继续往后进行比较交换操作,一趟下来使得序列中最大的数在最后边,假设长度是n,则第一趟将最大的数放在第n个位置上,然后再进行第二趟,第二趟下来之后保证除第n个数之外最大数在第n-1的位置,然后继续下一趟,重复上边操作,直到不需要继续元素交换了便排序结束了。

算法实现:

/*** 冒泡排序* @author chaizepeng*/
private static void bubbleSort1(int[] array) {int len = array.length;//控制比较的长度,最长len-1for (int i = len-1; i > 0; i--) {//第二层循环控制比较大小和交换位置for (int j = 0; j < i; j++) {if (array[j] > array[j+1]) {//如果前一个数比后一个数大,则交换位置int temp = array[j];array[j] = array[j+1];array[j+1] = temp;}}System.out.println("共有"+len+"个元素,这是第"+(len - i)+"趟");}
}/*** 冒泡排序* @author chaizepeng*/
private static void bubbleSort2(int[] array) {int len = array.length;//外层循环控制遍历趟数,最多循环len-1次for (int i = 0; i < len-1; i++) {for (int j = 0; j < len - 1 - i; j++) {//第二层循环控制比较大小和交换位置if (array[j] > array[j+1]) {//如果前一个数比后一个数大,则交换位置int temp = array[j];array[j] = array[j+1];array[j+1] = temp;}}System.out.println("共有"+len+"个元素,这是第"+(i+1)+"趟");}
}/*** 冒泡排序使用添加标记的方式进行优化,序列越接近有序,效率越高* @author chaizepeng*/
private static void bubbleSort3(int[] array) {int len = array.length;//标记boolean flag;//外层循环控制遍历趟数,最多循环len-1次for (int i = 0; i < len-1; i++) {flag = true;for (int j = 0; j < len - 1 - i; j++) {//第二层循环控制比较大小和交换位置if (array[j] > array[j+1]) {//如果前一个数比后一个数大,则交换位置int temp = array[j];array[j] = array[j+1];array[j+1] = temp;flag = false;}}System.out.println("共有"+len+"个元素,这是第"+(i+1)+"趟");//如果没有进行数据交换,也就是flag==trueif (flag) {break;//不再继续下一趟}}
}

算法分析:冒泡排序记住一点,只要没有元素交换了,则排序完成。

 

例如序列{1,2,3,4,5},第一趟比较4次,没有元素移动,时间复杂度O(n)

再例如序列{5,4,3,2,1},第一趟比较4次,移动12次,时间复杂度为O(n^2)

所以冒泡排序算法的时间复杂度在O(n)到O(n^2)之间,其时间复杂度与序列是否有序有直接关系,并且算法是稳定的。此算法每次都借助了一个临时的中间元素,用来交换两个数。

4、2 快速排序

算法描述:快速排序是对冒泡排序的优化,快速排序第一趟就根据某个元素将序列分成两部分,一部分中所有数据比此元素小,另一部分的所有数比此元素大或等于此元素;然后再对这两部分分别进行分割,整个过程可以递归进行,直到序列有序。

算法实现:

/*** 看图理解代码,一下子就全明白了* @author chaizepeng*/
private static void quickSort1(int[] array) {int i = 0;int j = array.length - 1;quickSort(i,j,array);
}/*** 递归实现快排算法* @author chaizepeng*/
private static void quickSort(int i, int j, int[] array) {int left = i;int right = j;int key = array[i];while (i < j) {//只要不相等就循环比较,交换操作//从右往左遍历while(i < j && array[j] >= key) {j--;}if (array[j] < key) {//每次交换的都是一个小于key的元素和key所在位置上的值,也就是key值int temp = array[i];array[i] = array[j];array[j] = temp;}//从左往右遍历while(i < j && array[i] <= key) {i++;}//交换i处和j处的数据if (array[i] > key) {//每次交换的都是一个大于key的元素和key所在位置上的值,也就是key值int temp = array[i];array[i] = array[j];array[j] = temp;}}//递归使用if (i > left) {quickSort(0, i, array);}if (j < right) {quickSort(j + 1, array.length-1, array);}
}

算法分析:

 这里写的快排是不稳定,快速排序算法效率受标记值(基准值)的影响,假如每次选择的基准值都是最值的话,那么就会导致被分割的子序列是不平衡的(一个里边就一个元素,另一个里边是其余的n-1个元素),则需要比较的趟数就会增加,导致算法效率低下,快排的时间复杂度在O(nlogn)到O(n^2)之间。所以想要提高快排的效率就要保证每次找的基准值是当前序列的中间值。

快排的空间复杂度在O(logn)到O(n)之间

5、选择排序

5、1 直接选择排序

算法描述:以升序为例:从第一个元素开始,依次比较序列中的元素,将最小的元素放在第一个位置;接着在第二个元素开始,依次比较序列中的值,将最小的元素放在第二个位置,依次类推,直到排序结束。

算法实现:

/*** 以升序为例:从第一个元素开始,依次比较序列中的元素,将最小的元素放在第一个位置;接着在第二个元素开始,依次比较序列中的值,将最小的元素放在第二个位置,依次类推,直到排序结束* 直接选择排序* @author chaizepeng*/
private static void straightSelectSort(int[] array) {//控制比较的趟数for (int i = 0; i < array.length - 1; i++) {int minFlag = i;//记录一下最小值所在的下标for (int j = i+1; j < array.length; j++) {//控制从何处开始比较,比较到何处结束if (array[j] < array[minFlag]) {//比较当前值和之前记录的最小下标对应的值minFlag = j;}}//将最小值放在最前边if (minFlag != i) {int temp = array[minFlag];//最小值array[minFlag] = array[i];//将当前值赋给最小值所在的位置array[i] = temp;//当前位置放最小值}}
}

算法分析:

直接选择排序,最多需要n-1趟,并且每一趟都需进行n-i此的比较,所以时间复杂度是O(n^2),并且直接选择排序是不稳定的算法。自我感觉这是最容易理解和实现的排序算法。

5、2 堆排序

算法描述:堆排序是对直接选择排序的一种优化,直接选择排序算法在每一趟比较两个数大小时, 只是比较大小没有做任何操作, 而堆排序针对此处做了优化,他在比较的同时也将其他的元素(不是最小的元素)做了相应调整。堆排序是先使用待排序的序列构建一个堆,这里用大顶堆来实现,然后根据大顶堆的特点,将根结点元素放到最后(这里实现升序排序),然后将剩下的元素再构成一个大顶堆,依次进行,直到堆的长度为1结束排序。

说一下什么是堆,堆是一种数据结构,首先是一个完全二叉树(有右子树必有左子树的二叉树),另外,这个完全二叉树的各个结点上的数值从根结点到每一个叶子结点都会有一种规律:
     父结点一定大于或者等于其孩子结点,这样的称为大顶堆
     父结点一定小于或者等于其孩子结点,这样的称为小顶堆

算法实现:

/*** * 堆排序:是对直接选择排序的一种优化,直接选择排序算法在每一趟比较两个数大小时, 只是比较大小没有做任何操作,* 		而堆排序针对此处做了优化,他在比较的同时也将其他的元素(不是最小的元素)做了相应调整。堆排序是先使用待排序的序列构建一个堆,这里用大顶堆来实现,* 		然后根据大顶堆的特点,将根结点元素放到最后(这里实现升序排序),然后将剩下的元素再构成一个大顶堆,依次进行,直到堆的长度为1结束排序。* 	存储堆时的数据下标在1开始,而不是0,因为可以直接使用二叉树的性质进行堆的构建	* @author chaizepeng*/
private static void heapSort(int[] array) {//这里已经-1了int len = array.length-1;//用待排序的序列构建一个大顶堆,因为排序是借助堆结构进行的,这里相当于初始化堆//存储序列的数组下标必须在1开始,根据平衡二叉树的顺序存储特性可以知道,len/2之后的是叶子节点,而len/2以及它前边的结点是存在子结点的//依次遍历每一个存在子结点的结点,然后进行判断、交换结点,使得构建一个堆//1、初始化最大堆for (int i = len/2; i > 0; i--) {heapAdjust(array, i, len);}for (int i = 1; i < array.length; i++) {System.out.print(array[i]+" ");}System.out.println("--------------------------");//2、交换根结点和最后一个结点位置,将剩下的重新构建一个堆for (int i = len; i > 1; i--) {//交换元素int temp = array[i];array[i] = array[1];array[1] = temp;heapAdjust(array, 1, i-1);}
}/*** 构建大顶堆* 什么是堆:* 	堆是一种数据结构,首先是一个完全二叉树(有右子树必有左子树的二叉树),另外,这个完全二叉树的各个结点上的数值从根结点到每一个叶子结点都会有一种规律:*      父结点一定大于或者等于其孩子结点,这样的称为大顶堆*      父结点一定小于或者等于其孩子结点,这样的称为小顶堆* @author chaizepeng*/
private static void heapAdjust(int[] array, int i, int len) {//遍历当前操作结点对应的子结点int j ;for (j = i * 2; j <= len ; j *= 2) {//记录一下当前操作的结点int temp = array[i];//子结点的左孩子和右孩子进行比较//这里为什么要比较一下呢?假设子结点比父节点大,则需要上浮子结点,但是有可能有左右两个结点,这里比较一下,确定哪一个结点上浮//此处j < len 必须要加if (j < len && array[j] < array[j+1]) {++j;}//如果当前操作的结点 > 子结点 ,不操作if (temp >= array[j]) {break;}//交换父子结点的值array[i] = array[j];array[j] = temp;//将需要判断的元素下标改成下降的元素下标,用于与其子节点进行判断i = j;}
}

 算法分析:

 堆排序的时间复杂度是O(n㏒n),算法是不稳定的。堆排序算法充分利用了完全二叉树的性质,效率高,比较复杂,不容易理解,比较适合元素多的序列排序使用。

6、归并排序

算法描述:归并排序使用的是算法设计中分治的思想,分而治之,然后合并,将小的子序列进行排序,然后慢慢的将有序的子序列进行合并,最终使得整个序列有序,这里介绍的是二路归并算法,也就是每次只将两个子序列进行归并。具体操作是这样的,每次是将两个序列A、B进行合并,这里假设这两个序列是有序的,首先初始一个长度为两个序列长度之和的容器,然后声明两个标记位i,j,i指向序列A的第一个元素,j指向序列B的第一个元素,然后比较两个数组中标记位上数的大小,哪一个小就将标记位上的数放到初始的容器中,然后将标记位指向下一个元素,然后直至其中一个序列中的元素已被移动完毕,则将另一个序列中的元素复制到容器中,排序完毕,这只是核心的两个序列归并逻辑。

算法实现:

public static void main(String[] args) {int []array = {24, 27 ,41, 44, 19, 47 ,50 ,5,65, 93 ,94 };for (int i = 0; i < array.length; i++) {System.out.print(array[i]+" ");}System.out.println();System.out.println("-----------------------------");//从第一个元素开始,第一次归并时,每一个归并的序列长度是1(默认每一个序列长度为1的序列是有序的)mergeSort(array,1);for (int i = 0; i < array.length; i++) {System.out.print(array[i]+" ");}
}/*** * @author chaizepeng** @param array 排序总序列* @param len 要归并的序列的长度*/
private static void mergeSort(int[] array ,int len) {//序列{6,5,8,4,7,9,2,1,4}要进行归并,第一次归并时需要将相邻的两个元素进行排序归并,分组如下//6,5,8,4,7,9,2,1,4//此时,需要比较两个相邻的元素,所以,就需要进行分组和排序//6,5  8,4  7,9  2,1  4//需要先判断一下要分几个组int count = array.length / (len * 2);//判断一下count的值,如果=0的话,则说明len*2已经大于序列总长度,这时序列已经排序完成,结束即可if (count == 0) {return;}//然后依次归并for (int i = 0; i < count; i++) {//i*len 第一个序列的第一个元素位置//len 有序序列长度//(2+i)*len 第二个序列的最后一个元素位置(不包括)merge(array,i*len*2,(i+1)*len*2,len);}//在这里判断一下是否归并正好两两对应,如果有剩下的,则也需要归并一下(这里是拿剩下的序列组和它的前一组进行归并操作)int rem = array.length % (len * 2);if (rem != 0) {merge(array, array.length-rem-len, array.length,len);}//进行完一次归并后,继续下一次操作//子序列长度为len的已经归并完成,下一次使用len*2作为长度继续归并mergeSort(array,len * 2);
}/*** 一次归并过程* @author chaizepeng** @param array* @param leftBegin* @param rightEnd* @param len*/
private static void merge(int[] array, int leftBegin, int rightEnd,int len) {//标记位,用于复制数组用int flag = leftBegin;//用一个数组来存一下需要合并的序列 int []temp = new int[rightEnd - leftBegin];int leftEnd = leftBegin + len;int rightBegin =leftEnd;//右边序列开始的位置//标记temp的下标int j = 0;//比较两个序列中的元素大小,进行填充while (leftBegin < leftEnd && rightBegin < rightEnd) {if (array[leftBegin] > array[rightBegin]) {temp[j++] = array[rightBegin++];}else {temp[j++] = array[leftBegin++];}}//判断一下前后两个被比较的序列那个还有元素剩余,则直接复制到temp中while(leftBegin < leftEnd) {temp[j++] = array[leftBegin++];}while(rightBegin < rightEnd) {temp[j++] = array[rightBegin++];}//将temp中的数据填到array中for (int k = 0; k < temp.length; k++) {array[flag+k] = temp[k];}
}

 算法分析:

 归并算法的时间复杂度是O(n㏒n),算法是稳定的,效率较高。

7、性能比较

没有绝对好的算法,要根据具体的情况来分析那个算法更好,平均情况下快排(个人比较喜欢快排)、堆排序和归并排序效率高;如果排序的序列基本有序,那么冒泡排序和直接插入排序效率比较高;如果序列基本逆序,则堆排序和归并排序效率高;在空间复杂度上看,堆排序是最好的。但是快排是最常用的。

附加一张算法指标对比表:

 

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

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

相关文章

用.NET Core实现装饰模式和.NET Core的Stream简介

该文章综合了几本书的内容.某咖啡店项目的解决方案某咖啡店供应咖啡, 客户买咖啡的时候可以添加若干调味料, 最后要求算出总价钱.Beverage是所有咖啡饮料的抽象类, 里面的cost方法是抽象的. description变量在每个子类里面都需要设置(表示对咖啡的描述).每个子类实现cost方法, …

动态规划训练20 [Treats for the Cows POJ - 3186 ]

Treats for the Cows POJ - 3186 简单的区间DP&#xff0c;就不解释了。 #include<iostream> #include<cstdio> using namespace std; const int INF1e9; const int maxn2005; int n, a[maxn]; int dp[maxn][maxn]; int main() {scanf("%d",&n);for(…

7、java中的面向对象思想和体现

java是一种面向对象的程序设计语言&#xff0c;在程序中使用对象来描述具体的事物&#xff0c;当多个事物具有共同的特点时&#xff0c;可以将事物的共同特点进行抽象&#xff0c;然后封装成一个包含事物共同特点的集合&#xff0c;在java中叫做封装成一个类&#xff0c;可以将…

jzoj1405-电缆建设【贪心,最小生成树】

正题 题目链接:https://jzoj.net/senior/#main/show/1405 题目大意 两个平行于xxx轴的线上有若干个点&#xff0c;求连接所有点需要多少距离的线。 解题思路 在同一平行线上的相邻的连边&#xff0c;然后在不同的上面的话就离最近的两个&#xff0c;跑最小生成树即可。 code…

动态规划训练21 [FatMouse and Cheese HDU - 1078 ]

FatMouse and Cheese HDU - 1078 这道题需要说一说&#xff0c;定义dp[x][y]表示从点(x,y)出发&#xff0c;每次走不超过k步&#xff0c;所能吃到的最大量。 有点难搞的是&#xff0c;这里递归的顺序不好确定&#xff0c;所以采用自顶向下的记忆化搜索的方式&#xff08;不用担…

这个拖后腿的“in”

问题之源C# 7.2推出了全新的参数修饰符in&#xff0c;据说是能提升一定的性能&#xff0c;官方MSDN文档描述是&#xff1a;Add the in modifier to pass an argument by reference and declare your design intent to pass arguments by reference to avoid unnecessary copyin…

P4310-绝世好题【位运算,dp】

正题 题目链接:https://www.luogu.org/problem/P4310 题目大意 一个长度为nnn的序列&#xff0c;求一个最长的子序列使得每个数&\&&前一个数不为0。 解题思路 因为是&\&&不为0&#xff0c;所以只要有一位都为1即可。 用fif_ifi​表示以第iii个结尾…

8、java中的内部类

根据类定义时所在的位置不同可以将内部类分为四大类&#xff1a;成员内部类、方法内部类、静态内部类、匿名内部类。 成员内部类 顾名思义成员内部类定义在外部类的成员变量位置&#xff0c;相当于外部类的一个成员。将成员内部类当成当前封装类中的一个成员即可&#xff0c;…

Surging 微服务框架使用入门

前言本文非 Surging 官方教程&#xff0c;只是自己学习的总结。如有哪里不对&#xff0c;还望指正。 我对 surging 的看法我目前所在的公司采用架构就是类似与Surging的RPC框架&#xff0c;在.NET 4.0框架上搭建Socket RPC&#xff0c;通过分组轮询的方式调度RPC&#xff0c;经…

动态规划训练22 [Milking Time POJ - 3616 ]

Milking Time POJ - 3616 说实话这道题目非常简单&#xff0c;本质上就是 多段有向图的求最大值问题。稍微变化的地方在于这个的的有向边没有那么明显 &#xff0c;而是需要自己去寻找 如果任务i到任务j之间存在有向边的话&#xff0c;那么一定有这个关系成立&#xff0c;即&a…

jzoj3888-正确答案【字符串hash,dfs】

正题 题目大意:https://jzoj.net/senior/#main/show/3888 题目大意 nnn个人mmm道题&#xff0c;已知道每个人的选项和有ppp个人满分和qqq个人零分&#xff0c;求字典序最小的可能的正确答案。 解题思路 用字符串hashhashhash判断即可。要注意的是如果没有一个人满分也没有一个…

9、java中的异常处理机制

Java中的异常&#xff08;Throwable&#xff09;分为两类&#xff1a;异常Execption和错误Error。 Error&#xff0c;也就是错误&#xff0c;这个是不可避免的&#xff0c;出现的问题使得应用停止&#xff0c;例如&#xff1a;服务器损坏、内存溢出等。在java中所有的错误都继承…

RabbitMQ教程C#版 - 工作队列

先决条件本教程假定RabbitMQ已经安装&#xff0c;并运行在localhost标准端口&#xff08;5672&#xff09;。如果你使用不同的主机、端口或证书&#xff0c;则需要调整连接设置。从哪里获得帮助如果您在阅读本教程时遇到困难&#xff0c;可以通过邮件列表联系我们。1.工作队列&…

动态规划训练23 [Making the Grade POJ - 3666 ]

Making the Grade POJ - 3666 这道题目有点意思。 我们定义dp[i][j]表示的含义是把包含前i个元素的子序列变成非递减的子序列&#xff0c;并且最后一个元素变成j所需要耗费的最小代价 那么状态转移方程可以写出来就是&#xff1a; dp[i][j] min(dp[i-1][k] abs(num[i] - j…

jzoj3889-序列问题【dp,高精度】

正题 题目链接:https://jzoj.net/senior/#main/show/3889 题目大意 一个序列nnn&#xff0c;求两个集合S,T∈[1..n]S,T\in[1..n]S,T∈[1..n]使得ax(x∈S)a_x(x\in S)ax​(x∈S)的xorxorxor和就是ay(y∈T)a_y(y\in T)ay​(y∈T)的andandand和&#xff0c;且x<y(x∈S,y∈T)x…

10、java中文件的抽象表示

java中使用File类来作为文件和目录路径名的抽象表示&#xff0c;是对于文件或者目录本身的属性来说的&#xff0c;而不是针对于文件的内容。 一些关于File类基本操作的代码如下&#xff1a; public class FileTest {/*** 可用于操作文件或者目录* author chaizepeng** param a…

IdentityServer4实战 - 基于角色的权限控制及Claim详解

一.前言大家好&#xff0c;许久没有更新博客了&#xff0c;最近从重庆来到了成都&#xff0c;换了个工作环境&#xff0c;前面都比较忙没有什么时间&#xff0c;这次趁着清明假期有时间&#xff0c;又可以分享一些知识给大家。在QQ群里有许多人都问过IdentityServer4怎么用Role…

动态规划训练24 [Phalanx HDU - 2859 ]

Phalanx HDU - 2859 这是一道非常好的题目&#xff0c;我实在是没想到该怎么做&#xff0c;看了一下大神的题解才恍然大悟&#xff08;还有这种操作&#xff1f;&#xff09; 由于对称矩阵是以对称轴进行对称的&#xff08;废话&#xff09;&#xff0c;所以我们可以用dp[i][j…

jzoj3890-长途旅行【同余最短路】

正题 题目链接:https://jzoj.net/senior/#main/show/3890 题目大意 nnn个点mmm条边的图&#xff0c;询问是否有111到nnn长度为TTT的路径。 解题思路 让WWW等于连接111的最小权值的两倍&#xff0c;然后用fi,jf_{i,j}fi,j​表示到第iii个点是否有权值%Wj\%Wj%Wj。然后用fi,T%W…

11、java中的I/O流(1)

我对于流的理解是这样的&#xff0c;计算机的本质本来就是对输入的数据进行操作&#xff0c;然后将结果输出的一种工具&#xff0c;数据在各个数据源节点之间进行流动&#xff0c;感觉流就是对这种状态的一种抽象&#xff0c;一个数据流表示的就是一系列数据序列&#xff0c;ja…