数据结构学习第一天<算法优劣的核心指标><常数时间操作><时间复杂度><额外空间复杂度><对数器><异或运算>
算法优劣的核心指标
时间复杂度(流程决定)
额外空间复杂度(流程决定)
常数项时间(实现细节决定,常忽略)
常数时间操作
执行时间固定的操作
常见的算数运算(+ - * / %等)
常见位运算(>>带符号右移 >>>不带符号右移全补0 << | & ^等)
赋值 比较 自增 自减
数组寻址 (Linked List不是,需要遍历数数)
时间复杂度
选择排序O(N^2)
package Demo01;
import java.util.Arrays;
//选择排序
public class Code01_SelectionSort {
public static void SelectionSort(int[]arr) {
if (arr==null||arr.length<2){
return;
}
for (int i = 0; i < arr.length-1 ; i++) {
//0——n-1找一次放第一个 1——n-1找一次放第一个...
int minIndex=i;//假设最小值在i上
for (int j=i+1;j< arr.length;j++){//i——N-1上找最小值下标
minIndex=arr[j]<arr[minIndex]?j:minIndex;
}
swap(arr,i,minIndex);
}
}
public static void swap(int arr[],int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void main(String[] args) {
int arr[]={6,2,5,7,4,3,8};
SelectionSort(arr);
System.out.println(Arrays.toString(arr));
}
}
冒泡排序 O(N^2)
package Demo01;
import java.util.Arrays;
//冒泡排序
public class Code02_BubbleSort {
public static void SelectionSort(int[]arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i=0;i<arr.length-1;i++){
for (int j = 0; j < arr.length-i-1 ; j++) {
if (arr[j]>arr[j+1]){
swap(arr,j,j+1);
}
}
}
}
public static void swap(int arr[],int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void main(String[] args) {
int arr[]={6,2,5,7,4,3,8};
SelectionSort(arr);
System.out.println(Arrays.toString(arr));
}
}
插入排序(最差情况) O(N^2)
package Demo01;
import java.util.Arrays;
//插入排序
public class Code03_InsertSort {
public static void SelectionSort(int[]arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i=1;i<arr.length;i++){
for (int j =i-1;j>=0&&arr[j]>arr[j+1];j--) {
swap(arr,j,j+1);
}
}
}
public static void swap(int arr[],int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static void main(String[] args) {
int arr[]={6,2,5,7,4,3,8};
SelectionSort(arr);
System.out.println(Arrays.toString(arr));
}
}
二分法相关(log2N)
package Demo01;
//二分法,在有序数组中找某个数是否存在
public class Code04_BSExit {
public static boolean exist(int[] sortedArr,int num){
if (sortedArr==null||sortedArr.length==0){
return false;
}
int L=0;
int R=sortedArr.length-1;
int mid=0;
while (L<R){
mid=L+((R-L)>>1);//mid=(L+R)/2 位运算比除运算快
if (sortedArr[mid]==num){
return true;
}else if (sortedArr[mid]>num){
R=mid-1;
}else {
L=mid+1;
}
}
return sortedArr[L]==num;//返回最边界的值
}
public static void main(String[] args) {
int[]arr={1,2,3,4,5,6,7};
System.out.println(exist(arr,8));
}
}
package Demo01;
//二分法,在有序数组中找>=某个数最左侧位置
public class Code05_BSNearLeft {
public static int NearestIndex(int []arr,int value){
int L=0;
int R=arr.length-1;
int index=-1;
while (L<=R){
int mid=L+((R-L)>>1);
if (arr[mid]<=value){//<=某个数
index=mid;
L=mid+1;//最右侧位置
}
else {
R=mid-1;
}
}
return index;
}
public static void main(String[] args) {
int[]arr={9,8,6,4,1};
System.out.println(NearestIndex(arr,6));
}
}
package Demo01;
//局部最小问题
public class Code06_BSAwesome {
public static int getLessIndex(int[] arr){
if (arr==null||arr.length==0){
return -1;
}
if (arr.length==1||arr[0]<arr[1]){
return 0;//左侧局部最小
}
if (arr[arr.length-1]<arr[arr.length-2]){
return arr.length-1;//右侧局部最小
}
int left=1;
int right= arr.length-2;
int mid=0;
while (left<right){
mid=(left+right)/2;
if (arr[mid]>arr[mid-1]){
right=mid-1;
}else if (arr[mid]>arr[mid+1]){
left=mid+1;
}else {
return mid;
}
}
return left;
}
public static void main(String[] args) {
int[]arr={9,7,5,8};
System.out.println(getLessIndex(arr));
}
}
额外空间复杂度
O(1) :流程中不需要开辟额外空间,只需要有限个几个变量完成任务
O(N):流程中需要开辟额外空间
对数器
package Demo01;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
int testTime=50000;
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);
Code01_SelectionSort.SelectionSort(arr1);
compare(arr2);
if (!isEqual(arr1,arr2)){
succeed=false;
System.out.println("出错样本:");
printArray(arr1);
printArray(arr2);
break;
}
}
System.out.println(succeed?"Nice!":"Shit!");
int[]arr=generateRandomArray(maxSize,maxValue);
printArray(arr);
Code01_SelectionSort.SelectionSort(arr);
printArray(arr);
}
public static int[] generateRandomArray(int maxSize,int maxValue){//产生随机数组
// Math.random() [0,1)
// (int)(Math.random()*N) [0,N-1]
int[]arr=new int[(int)((maxSize+1)*Math.random())];//长度随机
for (int i = 0; i <arr.length ; i++) {
arr[i]=(int)((maxValue+1)*Math.random())-(int)(maxValue*Math.random());//值随机 +1保证正数
}
return arr;
}
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;
}
public static void compare(int []arr){
Arrays.sort(arr);
}
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 void printArray(int arr[]){
System.out.println(Arrays.toString(arr));
}
}
异或运算
相同为0,不同为1(二进制不进位相加)
0^N==N N^N==0
满足交换律和结合律
a=a^b
b=a^b (不申请额外变量两个值【地址要不同】交换)
a=a^b
题目二
一个数组中有一种数出现了奇数次,其他数出现偶数次,怎么找到并打印这种数
题目二
把一个int类型的数,提取出最右侧的1来(N& ~N+1)
题目三
数组中有两种数出现了奇数次,其他数都出现偶数次,怎么找到并打印这两种数
(所有数异或起来就是奇数次的a异或b,不等于0,某个位i上有1,整个数组划分为两类,(1)第i位上为1的数(2)第i位上为0的数,a和b属于其中一类,若同属于一类奇+奇=偶,则i位会等于0,只异或(1)类的数可以找到eor'=a或b,随后eor eor‘就是另一个 a^b^a=b)
package Demo01;
public class Code07_EvenTimesOddTimes {
// arr中,只有一种数,出现奇数次
public static void printOddTimesNum1(int[] arr) {
int eor = 0;
for (int i = 0; i < arr.length; i++) {
eor ^= arr[i];//用异或除掉偶数次数
}
System.out.println(eor);//打印出奇数次数
}
// arr中,有两种数,出现奇数次
public static void printOddTimesNum2(int[] arr) {
int eor = 0;
for (int i = 0; i < arr.length; i++) {
eor ^= arr[i];
}
// a 和 b是两种数
// eor != 0
// eor最右侧的1,提取出来
// eor : 00110010110111000
// rightOne :00000000000001000
int rightOne = eor & (-eor); // 提取出最右的1 eor & (~eor+1) 最右侧的1剩下,其余变零
int onlyOne = 0; // eor'
for (int i = 0 ; i < arr.length;i++) {
// arr[1] = 111100011110000
// rightOne= 000000000010000
if ((arr[i] & rightOne) != 0) {//arr[i]上的最右侧那一位都是0
onlyOne ^= arr[i];//就是a和b的其中一个 eor'
}
}
System.out.println(onlyOne + " " + (eor ^ onlyOne));
}
public static int bit1counts(int N) {//二进制中1的个数
int count = 0;
// 011011010000
// 000000010000 1
// 011011000000
//
while(N != 0) {
int rightOne = N & ((~N) + 1);//提取最右侧1
count++;//提取一回就计数
N ^= rightOne;//抹掉最后右侧1
// N -= rightOne N若是负数不行
}
return count;//抹掉的数加最后一次计数
}
public static void main(String[] args) {
int a = 5;
int b = 7;
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println(a);
System.out.println(b);
int[] arr1 = { 3, 3, 2, 3, 1, 1, 1, 3, 1, 1, 1 };
printOddTimesNum1(arr1);
int[] arr2 = { 4, 3, 4, 2, 2, 2, 4, 1, 1, 1, 3, 3, 1, 1, 1, 4, 2, 2 };
printOddTimesNum2(arr2);
System.out.println(bit1counts(6));//110 两个1
}
}

浙公网安备 33010602011771号