个人算法笔记:
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] << " "; } }