0.排序相关辅助函数(重点:对数器)

1.简单排序的交换函数[位运算版]

(注意:位运算优先级较低,复合运算的时候需要加上小括号)

位运算一般较快.(但特殊情况自己与自己交换会变为0,如快排和堆排)

public static void swap(int[] arr, int i, int j) {
   arr[i] = arr[i] ^ arr[j];
   arr[j] = arr[i] ^ arr[j];
   arr[i] = arr[i] ^ arr[j];
}

普通版:(辅助变量temp,适合所有场景,较慢)

public static void swap(int[] arr, int i, int j) {
   int temp = arr[i] ;
   arr[i] = arr[j];
   arr[j] = temp;
}

加减版:(适合所有场景,中等,可能越界)

public static void swap(int[] arr, int i, int j) {
   arr[i] = arr[i] + arr[j];
   arr[j] = arr[i] - arr[j];
   arr[i] = arr[i] - arr[j];
}

2.取两数的平均值,中间值mid

普通版:(相加除2)

mid=(left +right)/2;

优化版1:(减小了越界的可能性)

mid=left +(right-left)/2;

优化版2:(位运算)

//>>右移,带符号 >>>右移,无符号 右移一位相当于/2
//注意位移运算外面的小括号,因为位运算优先级低
//位运算相对较快
int mid = left + ((right - left) >> 1);
//heapInsert中直接使用位运算计算父节点,会出现负数-1,数组下边越界
//当index=0时,parent=(index-1)/2 ;【parent=0】 parrent=(index-1)>>1;【parent=-1】
//while(index>0&&a[index]>a[((index-1)>>1)]){ //此时需要加上index>0

3.复制数组

1.直接用java系统函数

<1>copyOf(int[], int))**(int[] original, int newLength)

复制指定的数组,截取或用 0 填充(如有必要),以使副本具有指定的长度。
<2>copyOfRange(int[] original, int from, int to)
将指定数组的指定范围复制到一个新数组。

2.自写copyArray()

public static int[] copyArray(int[] arr) {
   if (arr == null) {
      return null;
   }
   int[] res = new int[arr.length];
   for (int i = 0; i < arr.length; i++) {
      res[i] = arr[i];
   }
   return res;
}

4.打印数组

public static void printArray(int[] arr) {
   if (arr == null) {
      return;
   }
   for (int i = 0; i < arr.length; i++) {
      System.out.print(arr[i] + " ");
   }
   System.out.println();
}

5.对数器

什么是对数器?

意义:

更快确定自写函数的正确性,直接输出错误用例,方便调试

方法:

1.写一个比较器,比较自写函数与绝对正确函数对数组处理后的结果;

2.比较次数、范围自定义后,数组长度随机,内部值随机(为方便调试,长度较小,次数多)

3.如果不同,返回false并打印不同的那次 原数组和自写函数排序后的数组

4.相同则返回true.因为次数足够多,样本量足够大,所以认为正确

对数器的概念和使用
0,有一个你想要测的方法a,
1,实现一个绝对正确但是复杂度不好的方法b,
2,实现一个随机样本产生器
3,实现比对的方法
4,把方法a和方法b比对很多次来验证方法a是否正确。
5,如果有一个样本使得比对出错,打印样本分析是哪个方法出错
6,当样本数量很多时比对测试依然正确,可以确定方法a已经正确。

比较器:比较两数组是否相等

<1>系统函数.equals

Arrays.equals(int[] a,int[] a2)

<2>自写比较

public static boolean isEqual(int[] arr1, int[] arr2) {
//特殊情况直接返回
   if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
      return false;
   }
   if (arr1 == null && arr2 == null) {
      return true;
   }
   if (arr1.length != arr2.length) {
      return false;
   }
   //核心代码:两个数组的比较
   for (int i = 0; i < arr1.length; i++) {
      if (arr1[i] != arr2[i]) {
         return false;
      }
   }
   return true;

生成器:生成随机数组

public static int[] generateRandomArray(int maxSize, int maxValue) {
    //长度在自定义范围内随机
   int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
    //数值在自定义范围内随机;可0,负数,正数
   for (int i = 0; i < arr.length; i++) {
      arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
   }
   return arr;
}

对数器使用:不同返回false和相应用例

int testTime = 500000;
int maxSize = 100;
int maxValue = 100;
boolean succeed = true;
for (int i = 0; i < testTime; i++) {
   int[] arr1 = generateRandomArray(maxSize, maxValue);
   int[] arr2 = copyArray(arr1);
   int[] arr3=  copyArray(arr1);
   bubbleSort(arr1);
   comparator(arr2);
   if (!isEqual(arr1, arr2)) {
      succeed = false;
      break;
   }
   if (succeed = false) {
      //原数组,出错测试数据
      printArray(arr3);
      //排错"后数组
      printArray(arr1);
      //"绝对正确"数组"
      printArray(arr2);
   }
}
System.out.println(succeed ? "Nice!" : "***ing ***ed!");