算法很美

算法很美

位运算的奇淫巧计

  1. 判断奇偶性
    • 所有的奇数 & 1 都是 1
    • 所有的偶数 & 1 都是 0
  2. 交换两个整数的值
    • ^三次。因为任何一个数异或自身为0,异或0为自身。
     int a = 32;
     int b = 43;
     int c = a^b;
     b=c^b;
     a=c^a;
     printf("%d%d",a,b);
  1. 例题解析

某个数组中除了某一个元素出现了一次外,其余元素皆出现了两次,请求出那个数

  • 思路:a ^ a = 0, a ^ 0 = a;
#include<stdio.h>

int main(){
	int n = 0;
	scanf("%d",&n);
	int arr[n];
	int temp=0;
	for(int i = 0 ; i< n;i++){
		scanf("%d",&arr[i]);
	}
	for(int i = 0 ; i< n;i++){
		temp^=arr[i];
	}
	printf("%d",temp);
	
	return 0;
} 

1-1000这1000个数放在大小为1001 的数组中
现有1001个数,其中有一个数重复,其余数皆只有一个,求重复的数

  • 思路:a[i]为(0-1000),则a[i]^(0-1000),消去了出现了2次的数
#include <stdio.h>
#include <stdlib.h>

int main(){
    int n = 1001;//n为数组的大小
    int arr[n];
    int i = 0;
    int temp=0;
    for(i=0;i<n-1;i++){
        arr[i]=i+1;
    }
    arr[n-1]=rand()%n+1;//生成1-1000的随机树
    for(i=1;i<=n-1;i++){
        temp=temp^i;
    }
    for(i=0;i<n;i++){
        temp=temp^arr[i];
    }
    printf("%d",temp);
}

输入一个整数,求该整数二进制中所包含的1的个数

  • 思路①: 辗转相除,求余数
#include <stdio.h>

int main(){
	int n = 0;
	scanf("%d",&n);
	int temp;
	int count = 0;
	while(n!=0){
		temp = n%2;//取余数
		n/=2;	
		if(temp==1){
			count ++;
		}
	}
	printf("%d",count);
	return 0;
} 
  • 思路②:x&(x-1) 消掉最近低位的1
#include <stdio.h>

int main(){
	int n = 0;
	scanf("%d",&n);
	int count = 0;
	while(n!=0){
		n=(n-1)&n;
		count++;
	}
	printf("%d",count);
	return 0;
} 

将整数的二进制的奇偶位互换

  • 思路:用i&1010保留偶数位的1,用i&0101保留奇数位的1
#include<stdio.h>

int main(){
	int n = 0;
	scanf("%d",&n);
	int ou = n&0xaaaaaaaa;//二进制 1010 1010 1010 1010 1010 1010 1010 1010 
	int ji = n&0x55555555;//二进制 0101 0101 0101 0101 0101 0101 0101 0101 

	printf("%d",(ou>>1)^(ji<<1));
	
	return 0;
} 

将十进制0~1的double类型小数,转换为二进制小数,若小数位数超过32位,则报error

/*
将0~1之间的小数转化为二进制,若二进制位数超过21位,则报error 
*/

#include<stdio.h>

int main(){
	char arr[32];
	double n;
	scanf("%lf",&n);
	int i = 0;
	while(n>0){	
		n*=2;
		if(n>=1){
			arr[i]=1;
			n-=1;
		}else{
			arr[i]=0;
		}
		i++;
		if(i>32){
			printf("error");
			return 0;
		}
	}
	printf("0.");
	for(int j = 0 ; j<i;j++){
		printf("%d",arr[j]);
	}
	
	return 0;
} 

思考:有一组数,其中有一个数出现1次,其余数出现k次,求出现1次的数 ()

  • 思路:k进制的k个数不进位相加位0
#include<stdio.h>

int main(){
	printf("暂时不会");
	return 0;
}

递归

  • 什么是递归
    • 编程语言中,函数Func(Type a,……)直接或间接调用函数本身,则该函数称为递归函数。递归函数不能定义为内联函数。
    • 在数学上,关于递归函数的定义如下:对于某一函数f(x),其定义域是集合A,那么若对于A集合中的某一个值X0,其函数值f(x0)由f(f(x0))决定,那么就称f(x)为递归函数。

  • 案例解析:

小白上楼梯(递归设计)
小白正在上楼梯,楼梯有n阶台阶,
小白一次可以上1阶,2阶或者三阶。
实现一个方法,计算小白有多少种走完楼梯的方式。

#include<stdio.h>
int fun(int len){
	if(len==0){
		return 0;
	}
	if(len==1){
		return 1;
	}
	if(len==2){
		return 2;
	}
	
	if(len==3){
		return 4;
	}
	if(len>3){
		return fun(len-1)+fun(len-2)+fun(len-3);
	}
} 

int main(){
	int n = 0;
	scanf("%d",&n);
	printf("%d",fun(n));
	return 0;
}

查找与排序

  • 二分查找
    • 二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
  • 要求:
  1. 必须采用顺序存储结构。
  2. 必须按关键字大小有序排列。

用递归形式实现二分查找

#include<stdio.h>

int binSearch(int arr[],int begin,int end,int key){
	int mid=begin+((end-begin)>>1);//注意这里的mid取值,为什么不是(begin+end)/2?
	if(end<begin){
		return -1;
	}
	if(arr[mid]<key){
		binSearch(arr,mid+1,end,key);//注意参数mid+1,为什么是mid+1?
	}
	else if(arr[mid]>key){
		binSearch(arr,begin,mid-1,key);//注意参数mid-1
	}else{
		return mid;
	}
	
}

int main(){
	int arr[]={1,3,5,7,14,23,90};
	printf("%d",binSearch(arr,0,7,3));
	
	return 0;
} 
  • 二分法(改造)

把一个数组最开始的若干元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小值。
例如{34512}为{12345}的一个旋转,该数组最小值为1.

#include<stdio.h>
#define MAX 10

int binarySearch(int arr[],int begin,int end){
	if(arr[end]>=arr[begin]){	//数组未旋转 
		return arr[begin];
	}
	int mid = begin+((end-begin)>>1);
	if(arr[mid]>arr[begin]){
		binarySearch(arr,mid,end);
	}else if(arr[mid]<arr[begin])
	{
		binarySearch(arr,begin,mid);
	}else{
		return arr[end];
	}
	
}

int main(){
	int arr[MAX]={79,2,3,4,5,7,12,43,65,76};
	printf("%d",binarySearch(arr,0,MAX-1));
	return 0;
}
  • 希尔排序
    • 希尔排序(Shell’s Sort)是插入排序的一种又称“缩小增量排序”(Diminishing Increment Sort),是直接插入排序算法的一种更高效的改进版本。希尔排序是非稳定排序算法。
#include<stdio.h>
#define MAX 10

void shellSort(int arr[]){
	for(int interVal =MAX/2;interVal>0;interVal/=2){
		for(int i=interVal;i<MAX;i++){
			int target = arr[i];
			int j = i-interVal;
			while(j>-1&&arr[j]>target){
				arr[j+interVal]=arr[j];
				j-=interVal;
			}
			arr[j+interVal]=target;
		}
	}
}

int main(){
	int arr[MAX]={12,43,54,6,3,12,43,5,65,76};
	shellSort(arr);
	int i = 0;
	while(i<MAX){
		printf("%d\t",arr[i]);
		i++;
	}
	return 0;
}

  • 分治法
    • 分治法可以通俗的解释为:把一片领土分解,分解为若干块小部分,然后一块块地占领征服,被分解的可以是不同的政治派别或是其他什么,然后让他们彼此异化。
    • 分治法的精髓:
      • 分–将问题分解为规模更小的子问题;
      • 治–将这些规模更小的子问题逐个击破;
      • 合–将已解决的子问题合并,最终得出“母”问题的解
  • 归并排序


树及二叉树
  • 二叉树的建立(三种遍历方法)
#include <stdio.h>
#define MAX 9
//先序遍历
void preArray(int *arr,int index){
    if(index>=MAX) return;
    printf("%d\t",arr[index]);
    preArray(arr,2*index+1);
    preArray(arr,2*index+2);
}
//中序遍历
void inArray(int *arr, int index){
    if(index>=MAX) return;
    inArray(arr,2*index+1);
    printf("%d\t",index);
    inArray(arr,2*index+2);
}
//后续遍历
void afterArray(int *arr, int index){
    if(index>=MAX) return;
    afterArray(arr,index*2+1);
    afterArray(arr,index*2+2);
    printf("%d\t",index);
}

int main(){
    int arr[MAX]={78,56,34,43,4,1,15,2,23};
    preArray(arr,0);
    inArray(arr,0);
    afterArray(arr,0);
    
    return 0;
}

  • 堆排序
#include<stdio.h>
#define MAX 9
void swap(int &a,int &b){
    int temp = a^b;
    a=temp^a;
    b=temp^b;
}

void maxheapTree(int *arr,int len,int index){
    int left = 2*index+1;
    int right = 2*index+2;
    int max=left;
    if(left>=len) return;
    if (right>=len){
        if(arr[index]<arr[max]) swap(arr[index],arr[max]);
        return;
    }
    if(arr[left]<arr[right]){
        max=right;
    }
    if(arr[index]<arr[max]) swap(arr[index],arr[max]);
    maxheapTree(arr,len,max);
}

void heapSort(int *arr,int len){
    int index = len/2-1;
    for(;index>=0;index--){
        maxheapTree(arr,len,index);
    }
    
}

void sort(int *arr,int len){
    while (len>0)
    {
        heapSort(arr,len);
        swap(arr[0],arr[--len]);
    }
    
    
}

int main(){
    int a[MAX]={2,23,43,4,56,1,15,34,78};
    sort(a,MAX);
    for (int i = 0; i < MAX; i++)
    {
         printf("%d\t",a[i]);
    }
    return 0;
}

多维数组与矩阵 ***

字符串专题 ****

基本数学问题 ****

递归、DFS、剪枝、回溯等 *****

贪心策略与动态规划 *****

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值