├── 002greedy.cpp ├── 002invest.cpp ├── 002knapsack1_recursion.cpp ├── 002knapsack2_dynamic.cpp ├── 004bubbleSort.cpp ├── 004heapSort.cpp ├── 004insertSort.cpp ├── 004mergeSort.cpp ├── 004quickSort.cpp ├── 012hanoi.cpp ├── 019binarySearch.cpp ├── 021chipTest.cpp ├── 023fibMatrix.cpp ├── 023power.cpp ├── 024largeMultiply.cpp ├── 024matrixMultiply.cpp ├── 025closestPair.cpp ├── 027findMaxMin.cpp ├── 027findMaxMin2.cpp ├── 028findSecond.cpp ├── 029selectK.cpp ├── 029selectK_simple.cpp └── README.md /002greedy.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | /* 6 | 代码作者:机智翔学长(B站,CSDN同名) 7 | 《算法设计与分析》(屈婉玲)视频地址:https://www.bilibili.com/video/av7134874 8 | 9 | 写在前面的话: 10 | 以前学习过该门课程,但没有认真实现相应的代码,仅仅以考试为目的。 11 | 现在想改过自新,重新学习,感谢互联网,感谢屈婉玲老师。 12 | 13 | 暂时的打算: 14 | 将该课程中所涉及到的算法,根据视频出现的顺序,实现一遍,录视频,传代码。 15 | 水平有限,若有不正确的地方,请指正。因为现在也有其他任务在身,不一定保证按时更新,但我尽量坚持下去,我们一起学习,希望能帮到你。 16 | */ 17 | 18 | bool cmp(int x, int y){ 19 | //默认情况,也可以不写,从小到大排序。 20 | //若写成 return x>y; 则从大到小排序。 21 | return x 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | #define MAX_N 4 //最大投资项目数目 8 | #define MAX_M 5 //最大投资钱数(万元) 9 | 10 | //投资问题 PPT 002 P9 11 | //代码参考 https://blog.csdn.net/qq_37337268/article/details/79826646 12 | //动态规划 13 | 14 | void getBestStrategy(int **mark); //声明函数,获取投资策略 15 | 16 | // 打印计算结果(调试) 17 | void printAns(int **dp, int **mark){ 18 | int i,j; 19 | for(i = 1; i <= MAX_N; i++){ 20 | for(j = 0; j <= MAX_M; j++){ 21 | printf("(%d,%d)\t", dp[i][j], mark[i][j]); 22 | } 23 | printf("\n"); 24 | } 25 | } 26 | 27 | //投资获取最大收益 28 | int getMaxValue(int f[MAX_N+1][MAX_M+1]){ 29 | //参考 二维数组作为函数参数传递 https://blog.csdn.net/weixin_41666244/article/details/80615661 30 | 31 | //dp[i][j]的意义:从1~i号项目中选择,投资j万元,所得到的最大收益 32 | int **dp = new int* [MAX_N+1]; 33 | //标记函数,mark[i][j]的意义:从1~i号项目中选择,投资j万元,获得最大收益时,在第i号项目中投资了多少钱 34 | int **mark = new int* [MAX_N+1]; 35 | 36 | for(int i=0;i<=MAX_N;i++){ 37 | dp[i] = new int[MAX_M+1]; 38 | //参考 C++二维动态数组memset()函数初始化 https://blog.csdn.net/longhopefor/article/details/20994919 39 | memset(dp[i], 0, (MAX_M+1)*sizeof(int)); 40 | 41 | mark[i] = new int[MAX_M+1]; 42 | memset(mark[i], 0, (MAX_M+1)*sizeof(int)); 43 | } 44 | 45 | //初始化第1行(第1个项目) 46 | for(int j=0;j<=MAX_M;j++){ 47 | dp[1][j] = f[1][j]; //因为只有1个项目,所以有多少钱j就投多少,对应收益为f[1][j] 48 | mark[1][j] = j; 49 | } 50 | 51 | int tmp; 52 | for(int i=2;i<=MAX_N;i++){ 53 | for(int j=0;j<=MAX_M;j++){ 54 | for(int k=0;k<=j;k++){ 55 | tmp = f[i][k]+dp[i-1][j-k]; 56 | if(tmp > dp[i][j]){ 57 | dp[i][j] = tmp; //更新当前最优解 58 | mark[i][j] = k; //更新标记函数 59 | } 60 | } 61 | } 62 | } 63 | 64 | printAns(dp, mark); 65 | getBestStrategy(mark); 66 | 67 | int res = dp[MAX_N][MAX_M]; 68 | 69 | //释放动态数组 70 | for(int i=0;i<=MAX_N;i++){ 71 | delete[] dp[i]; 72 | delete[] mark[i]; 73 | } 74 | 75 | delete[] dp; 76 | delete[] mark; 77 | 78 | return res; 79 | } 80 | 81 | //根据标记函数,获取具体的投资策略 82 | void getBestStrategy(int **mark){ 83 | //标记函数,mark[i][j]的意义:从1~i号项目中选择,投资j万元,获得最大收益时,在第i号项目中投资了多少钱 84 | 85 | //策略向量,项目逆序存储投资金额(即第4个项目投了多少,第3个项目投了多少,等等) 86 | vector strategy; // vector参考 https://www.runoob.com/w3cnote/cpp-vector-container-analysis.html 87 | int spend = 0; //已经花了多少钱 88 | for(int i=MAX_N;i>=1;i--){ 89 | strategy.push_back(mark[i][MAX_M-spend]); 90 | spend += mark[i][MAX_M-spend]; 91 | } 92 | 93 | reverse(strategy.begin(), strategy.end()); //逆序排列 94 | cout << "strategy: " ; 95 | for(int i=0;i 2 | using namespace std; 3 | 4 | //PPT P6 01背包问题 5 | //指定限制重量,求获得最大价值. 6 | //贪心法:X ppt上有反例 7 | 8 | //参考资料:《彻底理解0-1背包问题》 9 | //https://blog.csdn.net/chanmufeng/article/details/82955730 10 | 11 | // 01背包的递归解法 12 | int ks_recursion(int w[], int v[], int index, int capacity){ 13 | //ks_recursion() 表示将前index个物品放进容量为capacity的背包里,得到的最大的价值。index为数组下标。 14 | 15 | //基准条件:如果索引无效或者容量不足,直接返回当前价值0 16 | if(index < 0 || capacity <= 0) 17 | return 0; 18 | 19 | //不放第index个物品所得价值 20 | int res = ks_recursion(w, v, index-1, capacity); 21 | //放第index个物品所得价值(前提是:第index个物品可以放得下) 22 | if(w[index] <= capacity){ //放了,则一定有第index物品的价值v[index],同时也损失了背包的容量w[index] 23 | res = max(res, ks_recursion(w, v, index-1, capacity-w[index]) + v[index]); //选择价值大者 24 | } 25 | return res; 26 | } 27 | 28 | 29 | 30 | int memo[4][6] = {0}; //第一维为index,第二维为capacity 可能有更好的办法 31 | 32 | int ks_recursion2(int w[], int v[], int index, int capacity){ 33 | //在上面的基础上,加上 记忆化搜索 34 | if(index<0 || capacity<=0) 35 | return 0; 36 | 37 | //如果此子问题已经求解过,则直接返回上次求解的结果 38 | if(memo[index][capacity] != 0) 39 | return memo[index][capacity]; 40 | 41 | int res = ks_recursion2(w, v, index-1, capacity); //不放第index个物品 42 | if(w[index] <= capacity){ 43 | res = max(res, ks_recursion2(w, v, index-1, capacity-w[index])+v[index]); 44 | } 45 | 46 | //添加子问题的解,便于下次直接使用 47 | memo[index][capacity] = res; 48 | 49 | return res; 50 | } 51 | 52 | int main(){ 53 | 54 | int n = 4; //4件物品 55 | int w[n] = {3, 4, 5, 2}; //每件物品重量 56 | int v[n] = {7, 9, 9, 2}; //每件物品价值 57 | int capacity = 6; //限制重量(容量)为6 58 | int max_value = ks_recursion(w, v, n-1, capacity); 59 | cout << max_value << endl; 60 | 61 | int max_value2 = ks_recursion2(w, v, n-1, capacity); 62 | cout << max_value2 << endl; 63 | 64 | } -------------------------------------------------------------------------------- /002knapsack2_dynamic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //动态规划法 求解01背包 5 | //参考 https://blog.csdn.net/chanmufeng/article/details/82955730 6 | int ks_dynamic(int w[], int v[], int size, int capacity){ 7 | //size为物品的个数 8 | 9 | //C++用new创建二维数组的方法 10 | //dp[i][j]意义:从0~i件物品中选择,容量限制为j,求得的最大价值 11 | int **dp = new int *[size]; //参考方法二 https://blog.csdn.net/samuelcoulee/article/details/8674388 12 | for(int i=0;i=w[i];j--){ 54 | dp[j] = max(dp[j], dp[j-w[i]]+v[i]); 55 | } 56 | } 57 | 58 | int res = dp[capacity]; 59 | delete[] dp; 60 | 61 | return res; 62 | } 63 | 64 | int main(){ 65 | 66 | int n = 4; 67 | int w[n] = {3, 4, 5, 2}; //weight 68 | int v[n] = {7, 9, 9, 2}; //value 69 | int capacity = 6; 70 | int max_value = ks_dynamic(w, v, n, capacity); 71 | cout << max_value << endl; 72 | 73 | int max_value2 = ks_dynamic2(w, v, n, capacity); 74 | cout << max_value2 << endl; 75 | 76 | } -------------------------------------------------------------------------------- /004bubbleSort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | // 冒泡排序法 6 | void bubbleSort(int a[], int n){ 7 | int count = 0; // 计数外循环次数 8 | for(int i=n-1;i>=0;i--){ 9 | // 控制结尾的位置 10 | count += 1; 11 | for(int j=0;ja[j+1]){ 14 | // 如果逆序 15 | swap(a[j], a[j+1]); 16 | } 17 | } 18 | } 19 | cout << "count:" << count << endl; 20 | } 21 | 22 | // 简单改进的冒泡排序法。对于最好的情况,即数组本来就是有序的,再按照上述代码进行遍历,会浪费很多时间。 23 | // 故在此加入一个标志,如果本轮遍历未发生数据交换,就证明数组已然有序,直接结束循环。 24 | // 参考 https://blog.csdn.net/weixin_38427766/article/details/84779303 25 | void improvedBubbleSort(int a[], int n){ 26 | int flag; // 标志位 27 | int count = 0; // 计数外循环次数 28 | for(int i=n-1;i>=0;i--){ 29 | flag = 0; 30 | count += 1; 31 | for(int j=0;ja[j+1]){ 33 | // 如果发生逆序,则flag置为1 34 | flag = 1; 35 | swap(a[j], a[j+1]); 36 | } 37 | } 38 | if(flag==0){ 39 | // 如果flag为0,则说明没有发生逆序了,则可以停止了 40 | break; 41 | } 42 | } 43 | cout << "count:" << count << endl; 44 | } 45 | 46 | int main(){ 47 | int a[] = {5, 8, 1, 3, 6, 2, 4, 7}; 48 | int n = sizeof(a)/sizeof(int); 49 | bubbleSort(a, n); 50 | for(int i=0;i 2 | #include 3 | using namespace std; 4 | 5 | // 代码作者:机智翔学长(B站,CSDN同名) 6 | // 赠送内容,堆排序,从小到大排序,故大顶堆获取数据后放在末尾 7 | 8 | // 从下标l往下调整到r 9 | void adjustHeap(int a[], int l, int r){ 10 | if(l>=r){ 11 | return ; 12 | } 13 | int i = l; 14 | int j = 2*i+1; 15 | while(j<=r){ 16 | if(j+1<=r && a[j+1]>a[j]){ 17 | // i节点下的两个子节点j和j+1(如果存在),选择大的那个和i节点比较 18 | j = j+1; 19 | } 20 | if(a[j]>a[i]){ 21 | // 如果子节点j大于父节点i,则交换 22 | swap(a[i], a[j]); 23 | }else{ 24 | break; 25 | } 26 | i = j; 27 | j = 2*i+1; 28 | } 29 | } 30 | 31 | // debug 32 | void debugOut(int a[], int l, int r){ 33 | cout << "\ndebug out:" << endl; 34 | for(int i=l;i<=r;i++){ 35 | cout << a[i] << " "; 36 | } 37 | cout << endl; 38 | } 39 | 40 | // 堆排序,数组a[],下标为l~r (实际上l为0) 41 | void heapSort(int a[], int l, int r){ 42 | 43 | // 先构建一个大顶堆 44 | for(int i=(r-1)/2;i>=l;i--){ 45 | // i从最后一个父节点开始,往上 46 | adjustHeap(a, i, r); // 将数组a[]从i到r进行调整 47 | } 48 | 49 | // 再取出堆顶元素放在数组后边,重新调整堆 50 | for(int j=r;j>=l;j--){ 51 | swap(a[l], a[j]); 52 | debugOut(a, l, r); // debug 可删 53 | adjustHeap(a, l, j-1); 54 | } 55 | } 56 | 57 | int main(){ 58 | int a[] = {4, 6, 8, 5, 9}; 59 | int len = sizeof(a)/sizeof(int); 60 | heapSort(a, 0, len-1); 61 | cout << "\n\nafter sort:" << endl; 62 | for(int i=0;i 2 | using namespace std; 3 | 4 | void insertSort(int a[], int n){ 5 | if(n<=1) 6 | return ; 7 | int tmp; // 用来存储待插入的元素 8 | for(int i=1;i=0;j--){ 13 | // 需要将tmp和a[i-1~0]进行比较,直到找到比tmp小的位置为止 14 | if(a[j] > tmp){ 15 | // a[j]将元素右移一位 16 | a[j+1] = a[j]; 17 | }else{ 18 | // 找到合适位置 19 | break; 20 | } 21 | } 22 | // 将tmp填充在合适的位置 23 | a[j+1] = tmp; 24 | 25 | // debug 26 | for(int k=0;k 2 | using namespace std; 3 | 4 | // 将数组a中已经排好序的l1~r1 和 已经排好序的l2~r2 合并起来 5 | void merge(int a[], int l1, int r1, int l2, int r2){ 6 | int len1 = r1-l1+1, len2 = r2-l2+1; // 两段的长度 7 | int i = l1, j = l2, k = 0; 8 | int *merge_a = new int[len1+len2]; 9 | while(i<=r1 && j<=r2){ 10 | if(a[i]<=a[j]){ 11 | // 将较小的取出来放在merge_a中 12 | merge_a[k++] = a[i++]; 13 | }else{ 14 | merge_a[k++] = a[j++]; 15 | } 16 | } 17 | while(j<=r2){ 18 | // l1~r1这段走完了,只需将l2~r2这段后面的全部放在merge_a后面即可 19 | merge_a[k++] = a[j++]; 20 | } 21 | while(i<=r1){ 22 | // 同理,但两个while条件只会满足一个 23 | merge_a[k++] = a[i++]; 24 | } 25 | 26 | // debug 可删 27 | for(int m=0;m>1; //找到中间位置 43 | mergeSort(a, l, mid); //mid和mid+1中间要连起来,不能断裂 44 | mergeSort(a, mid+1, r); 45 | merge(a, l, mid, mid+1, r); 46 | } 47 | } 48 | 49 | int main(){ 50 | int a[] = {5, 8, 1, 3, 6, 2, 4, 7}; 51 | int n = sizeof(a)/sizeof(int); 52 | mergeSort(a, 0, n-1); 53 | cout << "\nafter sort:" << endl; 54 | for(int i=0;i 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | int partiton(int a[], int l, int r); 7 | 8 | void quickSort(int a[], int l, int r){ 9 | if(l s; 20 | s.push(r); 21 | s.push(l); 22 | while(!s.empty()){ 23 | int l2 = s.top(); 24 | s.pop(); 25 | int r2 = s.top(); 26 | s.pop(); 27 | 28 | int mid = partiton(a, l2, r2); 29 | if(l2pivot){ 45 | // 右边的严格大于,保证枢轴的右边均大于枢轴 46 | r--; 47 | } 48 | while(l 2 | using namespace std; 3 | 4 | void hanoi(char A,char C,int n, char B){ //将n个盘子从A全部帮到C中,B为辅助 5 | if(n==1){ 6 | cout << "move "<< n <<"st,from " << A << " to " << C < 2 | using namespace std; 3 | //参考https://github.com/zhang35/Algorithm-Design-And-Analysis/blob/master/%E7%AC%AC2%E7%AB%A0%20%E5%88%86%E6%B2%BB%E7%AD%96%E7%95%A5%20/%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.cpp 4 | 5 | int BinarySearch(int T[], int x, int n){ 6 | int l=0, r=n-1; 7 | while(l<=r){ 8 | int mid = (l+r)>>1; 9 | if(xT[mid]){ 12 | l = mid+1; 13 | }else{ 14 | return mid; 15 | } 16 | } 17 | return -1; 18 | } 19 | 20 | int main() 21 | { 22 | int T[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 12}; 23 | int n = sizeof(T)/sizeof(int); 24 | int x = 4; 25 | cout << "position: " << BinarySearch(T, x, n) << endl; 26 | return 0; 27 | } -------------------------------------------------------------------------------- /021chipTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | //来源于https://github.com/zhang35/Algorithm-Design-And-Analysis/blob/master/%E7%AC%AC2%E7%AB%A0%20%E5%88%86%E6%B2%BB%E7%AD%96%E7%95%A5%20/%E8%8A%AF%E7%89%87%E6%B5%8B%E8%AF%95.cpp 7 | 8 | struct Chip{ 9 | int label; //第几个芯片 10 | int state; //该芯片是好还是坏 11 | }; 12 | 13 | int ChipTestChip(list::iterator host, list::iterator guest); 14 | int ChipTest(list &chips); 15 | 16 | int main() 17 | { 18 | // cout << "input number of chips:" << endl; 19 | int n; 20 | // int sta[] = {0,1,1}; 21 | // int sta[] = {0,1,1,1}; 22 | // int sta[] = {0,1,1,1,1}; 23 | int sta[] = {0,1,1,1,0}; 24 | n = sizeof(sta)/sizeof(int); 25 | // cin >> n; 26 | list chips(n); 27 | list::iterator it; 28 | int i=0; 29 | // cout << "input "<< n << " states: 0->bad; 1->good" << endl; 30 | for (it=chips.begin(); it!=chips.end(); it++) { 31 | it->label = i+1; 32 | it->state = sta[i]; 33 | i++; 34 | // cin >> it->state; 35 | } 36 | cout << ChipTest(chips) << endl; 37 | return 0; 38 | } 39 | 40 | //2.3 芯片测试 41 | //重要结论1:若半数(含)以上芯片显示某芯片为好的,则它一定是好的; 42 | //因为好的占半数以上,如果是坏的会有半数以上显示其为坏的。 43 | //重要结论2:两两测试,如果均为好的(都好或都坏),则任丢一个;否则(至少有一个坏的)全丢掉 44 | //这样可以保证每次至少丢一个,且不同时丢掉两个好的;保证剩下的仍然好的占半数以上 45 | int ChipTestChip(list::iterator host, list::iterator guest){ //用host来测试guest 46 | if (host->state==1){ //如果host是好的,则能正确测试guest 47 | return guest->state; 48 | } 49 | else{ //否则随意 50 | return rand()%2; 51 | } 52 | } 53 | int ChipTest(list &chips){ 54 | unsigned long n = chips.size(); 55 | if (n<3){ //n为1,2,则均是好的。因为好的>坏的 56 | return chips.begin()->label; 57 | } 58 | list::iterator it1; 59 | list::iterator it2; 60 | if (n==3){ //3片 61 | it1 = chips.begin(); //选第1片 62 | it2 = chips.begin(); 63 | it2++; //选第2片 64 | if (ChipTestChip(it1, it2) & ChipTestChip(it2, it1)){ //若检测都说对方为好的 65 | return it1->label; //因为两者同好/同坏,但好>坏,所以只可能均为好。 66 | } 67 | else{ //否则it1和it2一好一坏,另一个肯定为好 68 | return 3; 69 | // return chips.end()->label; 70 | } 71 | } 72 | //当n为奇数时,单独判断轮空的最后一个,参考关键结论1 73 | //是好的,则结束;是坏的,则去掉 74 | if (n%2!=0){ 75 | it1 = chips.begin(); 76 | it2 = chips.end(); //C++的迭代器的end()指向最后元素的下一个位置 77 | it2--; //往前回溯一个 78 | int count = 0; 79 | for (int i=0; i= n/2){ 84 | return it2->label; 85 | } 86 | else{ 87 | cout << "pop :" << it2->label << endl; 88 | chips.pop_back(); 89 | n--; 90 | } 91 | } 92 | 93 | //相邻的两个为一组,从头到尾测试 94 | it1 = chips.begin(); 95 | for (int i=0; ilabel << " <-> " << it2->label; 100 | int r1 = ChipTestChip(it1, it2); 101 | int r2 = ChipTestChip(it2, it1); 102 | cout << " result: " << r1 << " " << r2 << endl; 103 | if (r1 & r2){ 104 | cout << "pop :" << it2->label << endl; 105 | it1 ++; 106 | it1 ++; //it1右移两位,到下一组 107 | chips.erase(it2); 108 | } 109 | //否则全丢掉 110 | else { 111 | cout << "pop: " << it1->label << " & " << it2->label << endl; 112 | it2++; 113 | chips.erase(it1, it2); //erase作用范围为[first,last) 114 | it1 = it2; 115 | } 116 | } 117 | //递归处理剩下的 118 | return ChipTest(chips); 119 | } -------------------------------------------------------------------------------- /023fibMatrix.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int** matrix(int **a,int **b){ 6 | int **c = new int* [2]; //创建c矩阵,存储a*b的结果 7 | for(int i=0;i<2;i++){ 8 | c[i] = new int[2]; 9 | } 10 | for(int i=0;i<2;i++){ //计算矩阵c 11 | for(int j=0;j<2;j++){ 12 | c[i][j] = a[i][0]*b[0][j] + a[i][1]*b[1][j]; 13 | } 14 | } 15 | return c; 16 | } 17 | 18 | int** power(int **a, int n){ //矩阵a的n次幂 n>=1 19 | if(n==1) 20 | return a; 21 | if(n%2==0){ //n为偶数 22 | int** tmp = power(a,n/2); //一半的结果 23 | return matrix(tmp,tmp); 24 | }else{ 25 | int** tmp = power(a,(n-1)/2); 26 | int** tmp2 = matrix(tmp,tmp); 27 | return matrix(tmp2, a); //要多乘以一个a 28 | } 29 | } 30 | 31 | int fib(int n){ 32 | if(n==0) 33 | return 0; 34 | else if(n==1) 35 | return 1; 36 | int res; 37 | int** base = new int* [2]; 38 | for(int i=0;i<2;i++){ 39 | base[i] = new int[2]; 40 | memset(base[i], 0, 2*sizeof(int)); 41 | } 42 | base[0][0] = 1; 43 | base[0][1] = 1; 44 | base[1][0] = 1; 45 | int** out = power(base, n); 46 | res = out[0][1]; 47 | 48 | for(int i=0;i<2;i++) 49 | delete[] base[i]; 50 | delete[] base; 51 | 52 | return res; 53 | } 54 | 55 | int main(){ 56 | for(int i=0;i<=10;i++){ 57 | int res = fib(i); 58 | cout << res << " "; 59 | } 60 | } 61 | 62 | //C++中将二维数组(静态的和动态的)作为函数的参数传递 https://www.cnblogs.com/usa007lhy/p/3286186.html 63 | //用vector来求解fib矩阵可以看 https://blog.csdn.net/Poe2017/article/details/82500439 64 | //其他参考 https://blog.csdn.net/xygy8860/article/details/47087687 -------------------------------------------------------------------------------- /023power.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //a的n次幂,n>=0 5 | int power(int a,int n){ 6 | if(n==1) 7 | return a; 8 | else if(n==0) 9 | return 1; 10 | if(n%2==0){ 11 | int x = power(a,n/2); 12 | return x*x; 13 | }else{ 14 | int x = power(a,(n-1)/2); 15 | return x*x*a; 16 | } 17 | } 18 | 19 | float func(int a,int n){ 20 | if(n<0){ 21 | return 1.0/power(a,-n); 22 | }else{ 23 | return power(a,n); 24 | } 25 | } 26 | 27 | int main(){ 28 | int a = 2; 29 | for(int n=-2;n<=2;n++){ 30 | float res = func(a,n); 31 | cout << a << "^" << n <<"=\t" << res << endl; 32 | } 33 | } -------------------------------------------------------------------------------- /024largeMultiply.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | int count=0; 5 | using namespace std; 6 | void SameNumber(); 7 | void UnSameNumber(); 8 | int SIGN(long A); 9 | long CalculateSame(long X, long Y, int n); 10 | long CalculateUnSame(long X, long Y, int xn, int yn); 11 | 12 | 13 | //代码来源于:https://www.cnblogs.com/little-kwy/archive/2017/09/30/7613642.html 14 | //原理可看:分治法的经典问题——大整数相乘 https://blog.csdn.net/jeffleo/article/details/53446095 15 | int main() 16 | { 17 | SameNumber(); 18 | UnSameNumber(); 19 | return (0); 20 | } 21 | 22 | int SIGN(long A) 23 | { 24 | return A > 0 ? 1 : -1; 25 | } 26 | 27 | void SameNumber() 28 | { 29 | cout<<"idea!"< 1) 195 | { 196 | 197 | while(M>=2) 198 | { 199 | M/=2; 200 | Count++; 201 | } 202 | 203 | M = N; 204 | 205 | if(M != (pow(2.0,Count))) 206 | { 207 | N = pow(2.0,Count+1); 208 | 209 | for(i=0; i=M) || (j>=M)) 214 | { 215 | A[i][j] = 0.0; 216 | B[i][j] = 0.0; 217 | } 218 | } 219 | } 220 | } 221 | } 222 | 223 | StrassenAlgorithm(A,B,C,N); // StrassenAlgorithm called here 224 | 225 | printf("Matrix A:\n\n"); 226 | WriteMatrix(A,M); 227 | printf("Matrix B:\n\n"); 228 | WriteMatrix(B,M); 229 | printf("The Product Of These Two Matrix:\n\n"); 230 | WriteMatrix(C,M); 231 | 232 | return 0; 233 | 234 | } -------------------------------------------------------------------------------- /025closestPair.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Filename:最邻近点对 3 | * 代码来源于https://github.com/king-wk/AlgorithmDesign/blob/master/Exercise3_C%2B%2B.cpp 4 | * Description: 采用分治算法 5 | * 分解:对所有的点按照x坐标、y坐标从小到大排序, 6 | * 根据下标分解,使点集分为两个集合 7 | * 递归寻找两个集合的最近点对,取它们最小值d 8 | * 合并:以中间点的x坐标mid划分一个[mid-d,mid+d]的区域,获取区域中所有的点 9 | * 遍历这些点,看是否存在距离小于d的点对 10 | */ 11 | #include 12 | #include 13 | #include 14 | #include 15 | using namespace std; 16 | /* 一个点对的最大距离 */ 17 | const double INF = 1e20; 18 | /* 点数 */ 19 | const int N = 30001; 20 | /* 点 */ 21 | struct Point { 22 | double x; 23 | double y; 24 | } 25 | point[N]; 26 | /* 实际输入的点数 */ 27 | int n; 28 | /* 用于记录位于区域[mid-d,mid+d]的点 */ 29 | int tmpt[N]; 30 | /** 31 | * 按照x坐标、y坐标的顺序比较两个点的大小 32 | */ 33 | bool cmpxy(const Point &a, const Point &b) { 34 | if ( a.x != b.x ) { //如果两个点x不相同,则按照x比较大小。否则按照y比较 35 | return(a.x < b.x); 36 | } 37 | return(a.y < b.y); 38 | } 39 | /** 40 | * 按照y坐标比较两个点的大小 41 | */ 42 | bool cmpy(const int &a, const int &b) { 43 | return(point[a].y < point[b].y); 44 | } 45 | /** 46 | * 返回两个double值中的最小值 47 | */ 48 | double min(double a, double b) { 49 | return(a < b ? a : b); 50 | } 51 | /** 52 | * 输出两个位置的点的距离的平方 53 | */ 54 | double dis(int i, int j) { 55 | double dis_x = point[i].x - point[j].x; 56 | double dis_y = point[i].y - point[j].y; 57 | return(dis_x * dis_x + dis_y * dis_y); 58 | } 59 | /** 60 | * 返回集合中的最小距离点对的距离 61 | * left:集合的左边界点位置,right:集合的右边界位置 62 | * 使用分治算法 63 | */ 64 | double Closest_Pair(int left, int right) { //left和right表示左右边界为第几个点/id号(并不是x坐标) 65 | /* 最小距离d */ 66 | double d = INF; 67 | /* 如果只有一个点,直接返回最小距离d */ 68 | if (left == right) { 69 | return(d); 70 | } 71 | /* 如果只有两个点,直接返回两个点的距离 */ 72 | if (left + 1 == right) { 73 | return(dis(left, right)); 74 | } 75 | /* 集合中间点的位置mid,根据mid将集合分成两部分 */ 76 | int mid = (left + right) / 2; 77 | /* 返回左边集合的最小距离点对的距离 */ 78 | double d1 = Closest_Pair(left, mid); 79 | /* 返回右边集合的最小距离点对的距离 */ 80 | double d2 = Closest_Pair(mid + 1, right); 81 | /* 取两个最小距离的最小值 */ 82 | d = min(d1, d2); 83 | int i, j, k = 0; 84 | /* 获取区域[mid-d,mid+d]的所有点 */ 85 | for (i = left; i <= right; i++) { 86 | if (fabs(point[mid].x - point[i].x) <= d) { //fabs()是对浮点数取绝对值 87 | tmpt[k++] = i; 88 | } 89 | } 90 | /* 将区域中的点按照y坐标排序 */ 91 | sort(tmpt, tmpt + k, cmpy); 92 | /* 遍历这个区域中的点,找到最小距离 */ 93 | for (i = 0; i < k; i++) { 94 | /* 95 | * 如果i点与j点的y坐标的距离大于d,那么i点与j点之后的点y坐标距离一定也大于d 96 | * 两个点的y坐标距离大于d,那么两个点的距离一定大于d,可以提前结束遍历 97 | */ 98 | for (j = i + 1; j < k && point[tmpt[j]].y - point[tmpt[i]].y < d; j++) { 99 | double d3 = dis(tmpt[i], tmpt[j]); //tmpt[i]指的是i对应的那个点的id号 100 | if ( d > d3 ) { 101 | /* 102 | * 如果有两个点对之间的距离小于d 103 | * 那么得到新的最小距离 104 | */ 105 | d = d3; 106 | } 107 | } 108 | } 109 | return(d); 110 | } 111 | int main() { 112 | // cin >> n; 113 | int n = 8; 114 | double a[8][2] = {{1,1},{2,2},{4,4},{8,8},{2,2.8},{5,6},{7,9},{11,11}}; 115 | for (int i = 0; i < n; i++) { 116 | // cin >> point[i].x >> point[i].y; 117 | point[i].x = a[i][0]; 118 | point[i].y = a[i][1]; 119 | } 120 | /* 根据点集的x坐标、y坐标将点集排序 */ 121 | sort(point, point + n, cmpxy); 122 | /* 输出最邻近点对距离的平方,并小数点后两位 */ 123 | cout << fixed << setprecision(2) << Closest_Pair(0, n - 1); 124 | return(0); 125 | } -------------------------------------------------------------------------------- /027findMaxMin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | //代码来源于https://github.com/zhang35/Algorithm-Design-And-Analysis/blob/master/%E7%AC%AC2%E7%AB%A0%20%E5%88%86%E6%B2%BB%E7%AD%96%E7%95%A5%20/%E5%90%8C%E6%97%B6%E6%89%BE%E6%9C%80%E5%A4%A7%E6%9C%80%E5%B0%8F%E5%80%BC.cpp 6 | 7 | void P(int a[],int n); //打印数组 8 | void FindMaxMin(int *S, int n, int* p_min, int* p_max); 9 | 10 | int main() 11 | { 12 | int n = 10; 13 | int S[]= {1,3,5,7,9,2,4,6,8,10}; 14 | P(S, n); 15 | int minValue = 0; 16 | int maxValue = 0; 17 | FindMaxMin(S, n, &minValue, &maxValue); 18 | cout << "Min is: " << minValue << endl; 19 | cout << "Max is: " << maxValue << endl; 20 | return 0; 21 | } 22 | void P(int a[],int n) 23 | { 24 | for(int i=0; iS[n-2]){ 51 | minValue = S[n-2]; 52 | maxValue = S[n-1]; 53 | } 54 | else{ 55 | minValue = S[n-1]; 56 | maxValue = S[n-2]; 57 | } 58 | n -= 2; 59 | } 60 | 61 | for (int i=0; iS[i+1]){ 63 | minValue = min(S[i+1], minValue); 64 | maxValue = max(S[i], maxValue); 65 | } 66 | else{ 67 | minValue = min(S[i], minValue); 68 | maxValue = max(S[i+1], maxValue); 69 | } 70 | } 71 | *p_min = minValue; 72 | *p_max = maxValue; 73 | } -------------------------------------------------------------------------------- /027findMaxMin2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | //分治算法 6 | //参考https://www.cnblogs.com/huashanqingzhu/p/3861016.html 7 | //在数组a的区间[i,j]范围内寻找一个最大值和一个最小值并通过指针*max和*min返回 8 | int findMaxMin(int *a,int i,int j,int *max,int *min){ 9 | int mid; 10 | int lmax,lmin,rmax,rmin; 11 | if(i==j){ 12 | *max = a[i]; 13 | *min = a[i]; 14 | return 0; 15 | }else if(i+1==j){ 16 | *max = std::max(a[i],a[j]); 17 | *min = std::min(a[i],a[j]); 18 | return 0; 19 | } 20 | mid = i+(j-i)/2; 21 | findMaxMin(a,i,mid,&lmax,&lmin); 22 | findMaxMin(a,mid+1,j,&rmax,&rmin); 23 | *max = std::max(lmax,rmax); 24 | *min = std::min(lmin,rmin); 25 | return 0; 26 | } 27 | 28 | int main(){ 29 | int S[]= {1,3,5,7,9,2,4,6,8,10}; 30 | int n = sizeof(S)/sizeof(int); 31 | int max,min; 32 | findMaxMin(S,0,n-1,&max,&min); 33 | cout << "min:" << min << endl; 34 | cout << "max:" << max << endl; 35 | } -------------------------------------------------------------------------------- /028findSecond.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | //PPT中的锦标赛算法 7 | //另外一种简单的,但时间复杂度更高的算法:https://github.com/zhang35/Algorithm-Design-And-Analysis/blob/master/%E7%AC%AC2%E7%AB%A0%20%E5%88%86%E6%B2%BB%E7%AD%96%E7%95%A5%20/%E6%89%BE%E7%AC%AC%E4%BA%8C%E5%A4%A7%E6%95%B0.cpp 8 | 9 | void P(list loser_list[], int S[], int n){ 10 | //打印 11 | for(int i=0;i::iterator it=loser_list[i].begin(); it!=loser_list[i].end(); it++){ 14 | cout << S[*it] << "->"; 15 | } 16 | cout << endl; 17 | } 18 | } 19 | 20 | int FindSecond(int S[], int Idx[], int n){ 21 | if(n<2) 22 | return 0; 23 | list loser_list[n]; //每个位置都有一个list,用来代替链表 24 | int k; //参与淘汰的元素数 25 | int m; 26 | k = n; 27 | while(k>=2){ 28 | if(k%2==1){ 29 | m = k/2+1; //下一轮,数组中元素的个数 30 | }else{ 31 | m = k/2; 32 | } 33 | int next_turn[m] = {0}; 34 | int j=0; 35 | for(int i=0;i/2 S[index_b]){ //S[index_a]要大 39 | loser_list[index_a].push_back(index_b); //将失败者index_b加在index_a后面 40 | next_turn[j++] = index_a; //将index_a存储在下一轮中 41 | }else{ 42 | loser_list[index_b].push_back(index_a); 43 | next_turn[j++] = index_b; 44 | } 45 | } 46 | if(k%2==1){ //如果k为奇数 47 | next_turn[j] = Idx[k-1]; //将最后一个index(轮空)存储到next_turn 48 | } 49 | k = m; 50 | for(int i=0;i::iterator it = loser_list[max_index].begin(); 58 | int second_value = S[*it]; //*it存储的是下标 59 | for(;it!=loser_list[max_index].end();it++){ 60 | second_value = max(second_value, S[*it]); 61 | } 62 | cout << "max value:" << max_value << endl; 63 | cout << "second_value:" << second_value << endl; 64 | } 65 | 66 | int main() 67 | { 68 | int n; 69 | int S[]= {5,3,6,7,2,1,4,8}; 70 | n = sizeof(S)/sizeof(int); 71 | int Idx[n] = {0}; 72 | for(int i=0;i 2 | using namespace std; 3 | 4 | //代码来源于https://github.com/tangsongbbb/AlgorithmsLearning/blob/master/%E4%BD%9C%E4%B8%9A6/6.1.c 5 | 6 | void insertSort(int R[], int low, int high) { //插入排序 7 | int i, j, tmp; 8 | for (i = low + 1; i <= high; ++i) { 9 | tmp = R[i]; //假设i指向第二个元素 10 | j = i - 1; //j指向第一个元素 11 | while (j >= low && R[j] > tmp) { //假设第一个元素>第二个元素 12 | R[j + 1] = R[j]; //第一个元素右移一位,此时第二个位置上为较大的数 13 | --j; //j指向下一个(前一个) 14 | } 15 | R[j + 1] = tmp; //把最后一次-1加回来,把第二个元素放在第一个位置上。 16 | } 17 | } 18 | 19 | int FindMid(int R[], int low, int high) { //找差不多值为中间的元素,和PPT中m*类似 20 | if (low == high) { 21 | return R[low]; 22 | } 23 | int i, k; 24 | for (i = low; i + 4 <= high; i += 5) { 25 | insertSort(R, i, i + 4); //用插入排序法(从小到大),排好R数组从i到i+4的数 26 | k = i - low; 27 | swap(R[low + k / 5], R[i + 2]); //R[low + k / 5]:第一组的数据,R[i + 2]:第i组的中位数 28 | } 29 | int n = high - i + 1; //最后面轮空的 30 | if (n > 0) { 31 | insertSort(R, i, high); 32 | k = i - low; 33 | swap(R[low + k / 5], R[i + n / 2]); 34 | } 35 | k = k / 5; 36 | if (k == 0) { //k<=4 不足一组时,返回第一个数 37 | return R[low]; 38 | } 39 | return FindMid(R, low, low + k); //下一轮的寻找 40 | } 41 | 42 | int FindId(int R[], int low, int high, int median) { 43 | for (int i = low; i <= high; ++i) { 44 | if (median == R[i]) { 45 | return i; 46 | } 47 | } 48 | return -1; 49 | } 50 | 51 | int Partion(int R[], int low, int high, int index) { //以R[index]为枢纽值,做一次划分操作,左边比它小,右边比它大 52 | if (low <= high) { 53 | swap(R[index], R[low]); 54 | int tmp = R[low]; 55 | int i = low, j = high; 56 | while (i != j) { 57 | while (j > i&& R[j] >= tmp) { 58 | --j; 59 | } 60 | R[i] = R[j]; 61 | while (i < j && R[i] <= tmp) { 62 | ++i; 63 | } 64 | R[j] = R[i]; 65 | } 66 | R[i] = tmp; 67 | return i; 68 | } 69 | return -1; 70 | } 71 | 72 | int Select(int R[], int low, int high, int K) { 73 | int median = FindMid(R, low, high); 74 | int index = FindId(R, low, high, median); 75 | int newIndex = Partion(R, low, high, index); 76 | int rank = newIndex - low + 1; 77 | if (rank == K) { 78 | return newIndex; 79 | } 80 | else if (rank > K) { 81 | return Select(R, low, newIndex - 1, K); 82 | } 83 | return Select(R, newIndex + 1, high, K - rank); 84 | } 85 | int main() { 86 | int i, n, k; //, d[100]; 87 | // cout << "Please input the amount:"; 88 | // cin >> n; 89 | // cout << "Please input the numbers:" << endl; 90 | // for (i = 0; i < n; i++) { 91 | // cin >> d[i]; 92 | // } 93 | // cout << "Please input k:"; 94 | // cin >> k; 95 | int d[] = {8,2,3,5,7, 6,11,14,1,9, 13,10,4,12,15}; 96 | n = sizeof(d)/sizeof(int); 97 | k = 6; 98 | int index; 99 | index = Select(d, 0, n - 1, k); 100 | cout << "the number is: " << d[index] << endl; 101 | } -------------------------------------------------------------------------------- /029selectK_simple.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | //代码参考https://github.com/zhang35/Algorithm-Design-And-Analysis/blob/master/%E7%AC%AC2%E7%AB%A0%20%E5%88%86%E6%B2%BB%E7%AD%96%E7%95%A5%20/%E6%89%BE%E7%AC%ACk%E5%B0%8F%E6%95%B0%E5%8F%8A%E4%B8%AD%E4%BD%8D%E6%95%B0%E2%80%94O(n)%E5%A4%8D%E6%9D%82%E5%BA%A6.cpp 5 | //找第k小,简化版 6 | 7 | void P(int a[],int n); //打印数组 8 | int SelectK(int *S, int l, int r, int k);//找第k小数 9 | 10 | int main() 11 | { 12 | int n = 10; 13 | int S[]= {1,3,5,7,9,2,4,6,8,10}; 14 | P(S, 10); 15 | int k; 16 | // cout << "input k:"; 17 | // cin >> k; 18 | k = 6; 19 | cout << "the " << k << "th min number is: " << SelectK(S, 0, n-1, k) << endl; 20 | return 0; 21 | } 22 | void P(int a[],int n) 23 | { 24 | for(int i=0; i=x){ 35 | j--; 36 | } 37 | if (i k) { 60 | return SelectK(S, l, pivot-1, k); 61 | } 62 | return SelectK(S, pivot+1, r, k-rank); 63 | 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # video-Algorithm-QWL 2 | 算法设计与分析(屈婉玲)配套视频的代码讲解 3 | 视频讲解: https://www.bilibili.com/video/BV1Eh411Z7Ad 4 | 5 | 欢迎关注bilibili 机智翔学长 6 | 7 | --------------------------------------------------------------------------------