第一讲:时间复杂度与简单排序算法
. 时间复杂度的O表示一个最坏情况,上限
. 两个同时间复杂度的算法进行比较要实际测试
· O(log2^N)默认为以2为底
. 异或(^
)可以理解为无进位相加(可解释异或的交换性质)。
· 0^
a=a,a^
a=0
. 二分法不一定要在有序数组中运用(找局部最小值)
用异或交换数字
注意用异或的交换和结合性质理解
a=a^b;
b=a^b; //b=a^b^b=a^0=a;
a=a^b; //a=a^b^a=a^a^b=0^b=b;
.异或高阶运用
异或运算偶数次的同一数为0,奇数次为本身
提取最右侧的1:
int rightone=eor & (~eor+1);
对数器
1.有想测的方法a,另外有已知不好的方法b
2.生成随机样本产生器
3.样本在a,b中都测试一遍。看结果是否相同。(先小样本,人工看。再大数据量测)
选择排序
for(int i=0;i<len;i++){
int minIndex=i;
for(int j=i;j<len;j++){
minIndex=arr[j]<arr[minIndex]?j:minIndex;
}
swap(arr,i,minIndex);
}
}
冒泡排序
for(int i=len-1;i>0;i--){
//指定最开始的范围
for(int j=0;j<i;j++){
if(arr[j]>arr[j+1]){
swap(arr[j],arr[j+1]);
}
}
}
插入排序
for(int i=1;i<arr.length;i++){
//每步想要完成的目标
for(int j=i-1;j>=0&&arr[j]>arr[j+1];j--){
//j是目标的前一个数字
swap(arr[j],arr[j+1]);
}
}
/*关于第二层for循环中&&可以理解为,有一个没达到条件就终止循环,
这是很严格的,所以用&&表示这种严格程度
*/
第二讲:认识O(NlogN)的排序
·Mid常规写法:(L+R)/2 —>可能会溢出;所以用Mid=L+(R-L)/2或者L+(R-L)>>1
·递归可以理解为后序遍历树,悬而未决的函数进栈(压栈push)
·递归函数Master公式:T(N)=a*T(N/b)+O(N^
d)
----》a为子问题调用次数,b为子问题是母问题数据量的倍数,O(N^
d)是函数剩余的时间复杂度
·利用Master公式求时间复杂度:
logb^a<d :O(N^d)
logb^a>d :O(N^logb^a)
logb^a=d :O(N^d*logN)
归并排序
·归并排序的核心是双指针,一个指向头,一个指向中间+1位置。不断找最小的拷贝到新数组中。直到一个指针到了头(前指针到中间或者后指针到尾巴),再把另一个未到头的直接拷贝进新数组。实现了区域小块的排序。
·递归的本质就是不断把需要排序的区域缩小化,中间mid作为下一个区域的边界。
public static void process(int[] arr,int L,int R){
if(L==R)return;
int mid=L+((R-L)>>1);//这样算中点可以防止溢出,>>优先级比+低
process(arr,L,mid);
process(arr,mid+1,R);
merge(arr,L,mid,R);
}
public static void merge(int[]arr,int L