《算法十二》(个人笔记)

个人算法笔记:

STL:标准模板库
Standard Template Library

	STL概述:
		序列式容器:数据无序
			vector数组
			list双向链表
			deque双向动态队列
		关系式容器:数据有序
			map 
			set
			multimap
			multiset
		
		容器都有的功能:增删改查
		容器都有的函数:
			构造、析构、插入、删除
			查找、拷贝构造、元素个数......
		
		迭代器:返回地址
			迭代器:用来定位容器中某个元素
					数组:下标
					链表:next指针
					容器:智能指针
					
			迭代器返回值:是容器中元素的地址
						  因此每次使用最好初始化begin()
			
			迭代器.begin():指向第一个元素的地址
			迭代器.end():指向最后一个元素的后面
			容器.insert(迭代器, 数据):插入
			如果容器发生改变,迭代器会失效
			
		List:双向动态链表
		
		数组&&链表:数组查找高效
					链表插入删除高效
					数组连续,链表不连续
		
		deque:双向动态队列
			   介于数组和链表之间
	
	排序算法:shell排序/基数排序/桶排序
		shell排序:
			1.优化后的插入排序
			2.按步长step分组:步长一开始设置为元素个数/2
			3.组内插入排序
			4.步长=步长/2
			
		基数排序:
			1.创建临时数组
			2.初始化临时数组
			3.临时数组排序
			4.将临时数组值赋值回原数组
			5.delete临时数组
			限制:1.不能有重复运算
				  2.空间浪费大
			优点:不需要经过比较

		桶排序:基数排序的升级
			1.根据数据范围获取排序次数
			2.制作桶并且初始化
			3.遍历a数组并且按照排序依据将a数组元素存到桶里
			4.放回原来数组里
		总结:希尔排序速度快,不稳定
			  桶排序速度快,稳定,但是空间复杂度高
		
		
		分治:分而治之
		二分查找:折半查找
		归并排序:两个有序数组合并为一个有序数组
		
		归并排序:
			递归的拆分+合并
			合并:
				1.准备临时数组
				2.将数据元素依序放到临时数组中
				3.将数据元素从临时数组拷贝回到原数组中,释放临时数组
				
		二分查找:有序数组按照二分方式来查找数据
			递归方法:int mid = l + (r-l)/2;//中间 
					  if(l==r) return -1;//没有找到的情况,此时l==r 
					  if(finddata==a[mid]) return mid;
					  if(finddata>a[mid]) half_find(a, mid+1, r, finddata);
					  if(finddata<a[mid]) half_find(a, l, mid, finddata);
					  
			非递归方法:int mid;
						int left = l;
						int right = r;
						while(left < right){
							mid = left + (right-left)/2;
							if(finddata == a[mid]) return mid;
							if(finddata > a[mid]){
								left = mid+1;
							}else{
								right = mid;
							}
						}
						return -1;//没有找到的情况,此时left==right 
		
			递归练习之汉诺塔问题:
				if(num<1) return;//num不符合实际的情况 
				han_nuo(num-1, A, C, B);
				printf("%c-->%c 
", A, C);
				han_nuo(num-1, B, A, C);
			
			二分查找与归并排序总结:
				都是分治思想
				二分:每次排除一半
				归并:拆分成为2个,递归的进行拆分直到都成为有序数组
					  然后合并有序数组————>排序成功
				
		
		N叉树:
			一棵树有多个分叉
			森林:多棵树
			节点:树中的元素,子树
			枝干,叶子节点,路径长度
			层:根节点到某些结点的路径长度相同,同一层
			
			N叉树的增删改查
			
		
		有序二叉树:
			二叉树:每个节点有且只有2个孩子
			有序二叉树:左孩子<根<右孩子
			叶子节点:没有孩子的节点
			
		
		
		寻路算法:
		1.深度寻路算法:
			二维地图:二维数组
				二维数组上标识特定数值作为地图上对象	
			
			应用于RGB游戏中比较广泛
			缺点:1.二维地图,只可以走直线
				  2.不一定能找到最佳路径
				  
		
		2.广度寻路算法:
			遍历整个地图中所有可以走的点
			并且将其存入到一颗四叉树里
			之后从起点开始搜索这棵树查找终点即可
		
		小总结:
			深度寻路:
				有回退	循环少   适用于宽阔大地图   不一定能找到最短路径
			广度寻路:
				没有回退  循环多   适用与小地图     一定能找到最短路径
			但是都只能走直线
			
		3.A星寻路:
			结构:N叉树
			直线代价斜线代价:符合勾股定理
			代价:每走一步,距离终点所付出的
			 f = g + h + w;
			 f : 当前点到终点的代价
			 g : 起点到当前点的代价
			 h : 当前点到终点的预估代价(只计算直线距离,并忽略障碍)
			 w : 权重  路:   平地    上坡路  丘陵  沼泽   坑 
			
		
	动态规划:
		使用动态规划:重叠子问题
		最优值,最佳解
		斐波那契数列问题
		
	背包问题:
		当背包重量==0:什么也不能偷
		B(i, j):i代表还有几件商品可以偷
				j代表还剩下的背包空间是多少
		


机试准备:
  1.setfill/setw使用
  float f1 = 2.99;
  float f2 = 8.9099;
  int i = 10;
  cout << setfill('*');
  //setw是设置域宽,就是输出数据所占几列
  //如果在默认的情况下,输出的数据不能达到所规定的域宽就用空格填充
  //setfill是设置填充物
  //使用操纵符时,需要包含头文件iomanip
  cout << setw(10) << f1 << endl;
  cout << setw(10) << f2 << endl;
  cout << setw(10) << i << endl;
 
  2.定义结构体
  struct Student{
      int id;
      char name[20];
  };
  可以使用typedef添加别名
  typedef struct Student{
      int id;
      char name[20];
  }Student;
 
  使用:Student s; 
 
  3.关于字符串读取
  string str = "hello gy";
  int i = 0;
  while(str[i] != ''){
      cout << str[i] << endl;
      i++;
  }
 
  4.排序问题
  复试不要求一般用:冒泡排序
  int len = 6;
  int num[] = {5,2,77,1,99,66};
  for(int i=0; i<len-1; i++){
      for(int j=0; j<len-1-i; j++){
          if( num[j]>num[j+1] ){
              int temp = num[j];
              num[j] = num[j+1];
              num[j+1] = temp;
          }
      }
  }
  for(int i=0; i<len; i++){
      cout << num[i] << " ";
  }
 
  5.数字和字符之间转换
      例如:将字符'7'转为数字7
      char a = '7';
      int a_num = a - '0';
      例如:将数字 5 转换成字符'5'
      int b_num = 5;
      char b = b_num + '0';
 
  6.进制转化:10进制转8进制
  int num = 666;
  int result[100];
  int len = 0;
  while(num/8 != 0){
      result[len] = num%8;
      len++;
      num /= 8;
  }
  result[len] = num;
  for(int i=len; i>=0; i--){
      cout << result[i] <<endl;
  }
 
  7.质数判断
  int num = 10;
  int temp = sqrt(num);
  bool isZhiShu = true;//默认是质数
  for(int i=2; i<=temp; i++){
      if( num%i==0 ){
          isZhiShu = false;//不是质数
          break;
      }  
  }
  if(isZhiShu){
      cout << "是质数" << endl; 
  }else{
      cout << "不是质数" << endl;
  }
 
  8.字符串拷贝函数strcpy
  char *strcpy(char *dest, const char *src);
  将参数 src 字符串拷贝至参数 dest 所指的地址
  char string[10];
  char *str1 = "abcdefgh";
  //将str1的内容拷贝给string数组
  strcpy(string, str1);
  printf("%s
", string);
 
  9.字符串拼接函数strcat
  char *strcat(char *dest, const char *src);
  作用:返回dest字符串起始地址,并且dest = dest+src
  char str[20];
  char* str1 = "gyy";
  char* str2 = "wgg";
  strcat(str, str1);
  strcat(str, str2);
  printf("%s
", str);
 
  10.字符串比较函数strcmp
  int strcmp(const char *s1, const char *s2);
  若s1==s2返回0;s1>s2返回大于0;s1<s2返回小于0
  char *a = "aBcDeF";
  char *b = "AbCdEf";
  char *c = "aacdef";
  char *d = "aBcDeF";
  printf("%d
",strcmp(a,b));
  printf("%d",strcmp(a,d));
     
  11.计算字符串长度函数strlen
  计算指定的字符串长度,不包括结束字符'' a
  size_t strlen(const char *s);
  返回字符串s的字符数
  但是sizeof返回的是变量声明后所占的内存数,不是实际长度
  char str[5] = "abcd";
  cout << strlen(str) << endl;//4
  cout << sizeof(str) << endl;//5
 


 
基本冒泡排序:
    for(int i=0; i<n-1; i++){
        for(int j=0; j<n-1-i; j++){
            if(a[j]>a[j+1]){
                int temp = a[j];
                a[j] = a[j+1];
                a[j+1] = temp;
            }
        }
    }
基本二分查找:
    int left = 0;
    int right = len - 1;
    int mid;
    while( left<=right){
        mid = left + (right - left)/2;//防止溢出
        if(find_data == a[mid]){
            return mid;
        }else if(find_data > a[mid]){
            left = mid + 1;
        }else{
            right = mid - 1;
        }
    }
    return -1;//没有找到
基本选择排序:
    从待排序的数据中选出最小的元素放在起始位置,然后再从剩余的未排序元素中寻找到最小的元素,放到已排序的序列的末尾
    1.我们的目标是找到最小的数min,放到第一位
    2.我们的目标是,找出除了min以外的最小值,让它排在第2位
    3.重复2直到结束
    for(int i=0; i<a.length-1; i++){//需要几轮,例如a=[1,2,3,4,5]需要4轮,最后一个肯定是最大值
        //每轮遍历开始前,默认第一个数为最小值
        int min = a[i];
        int minIndex = i;
        for(int j=i+1; j<a.length; j++){
            if(min>a[j]){
                min = a[j];
                minIndex = j;//记录下标
            }
        }
        //如果最小值改变了,那么交换
        if(min!=a[i]){
            a[minIndex] = a[i];
            a[i] = min;
        }
    }
基本插入排序:
	void insertSort(int a[], int n){
	for(int i=1; i<n; i++){//默认第一个元素a[0],只有一个数,有序 
		int temp = a[i];//存储当前要插入元素
		int j = i - 1;
		while( j>=0 && temp<a[j] ){//从后往前找合适位置 
			a[j+1] = a[j];//没找到,元素后移 
			j--;
		}
		//此时找到了合适位置
		//每次没找到都j--所以最后插在j+1位置 
		a[j+1] = temp; 
	}
	//打印 
	for(int i=0; i<n; i++){
		cout << a[i] << " ";
	} 
}
原文地址:https://www.cnblogs.com/Whgy/p/12301431.html