好的代码应该是简单直接、逻辑清晰的,bug 难以隐藏的。即时没有注释读一遍也能看懂。 而烂代码逻辑混乱,写完过段时间本身都看不懂。ios
这里从一些问题出发对比好代码烂代码,但愿你们共同提升。数组
问题描述[1]函数
有一个矩形的房间里铺满正方形瓷砖。每块瓷砖涂成黑色或红色。一我的站在黑色的瓷砖上,今后出发,能够移动到四个相邻的瓷砖之一,但只能移动到黑色的瓷砖上。计算他经过重复上述移动所能通过的黑砖数。spa
这里把红色改为了白色,其余不变。思路原做者描述的很详细了。.net
/* 样例输入输出 6 9 //列数、行数 BBBBWB BBBBBW BBBBBB BBBBBB BBBBBB BBBBBB BBBBBB W@BBBW BWBBWB 45 0 0 //结束标志 */
这里对比一下个人实现(烂代码)和原做者的实现(好代码)code
#include<iostream> #include<cstdio> #include<string> #include<vector> using namespace std; int g=0; vector<vector<bool> > isvisit; /*1. 因为每次输入的是字符串,考虑用vector<string>表示该二维矩阵,cin>>str输入每行。 用char a[][];cin>>a[i] 更方便*/ void reach(vector<string>&v,int x,int y,int h,int w) { if(isvisit[x][y] || v[x][y]=='W') return; g++; isvisit[x][y]=true; //cout<<x<<" "<<y<<" "<<g<<" "<<v[x][y]<<endl; /*2. 探索函数,顺序为左右上下 把全部边界条件写到函数入口更好更方便。*/ //left if(y>0 ) reach(v,x,y-1,h,w); //right if(y<w-1 ) reach(v,x,y+1,h,w); //up if(x<h-1) reach(v,x+1,y,h,w); //down if(x>0 ) reach(v,x-1,y,h,w); } int main() { int w,h;//width height//列数、行数 while(cin>>w>>h) { if(w==0 && h==0) break; vector<string> v(h,"");//1. 初始化矩阵v // true: visited //初始化二维vector isvisit=vector<vector<bool> >(h,vector<bool>(w,false)); int sx=0; int sy=0; bool isfindat=false; for(int i=0;i<h;i++) { cin>>v[i]; if(isfindat==false) { for(int j=0;j<v[i].size();j++) { if(v[i][j]=='@') { sx=i; sy=j; isfindat=true; } } } } g=0; reach(v,sx,sy,h,w); cout<<g<<endl; } } */
原做者blog
#include <iostream> #include<cstring> using namespace std; // R 红砖 B 黑砖 @人 const int MAX_ROW = 20, MAX_COLUMN = 20; int sum, m, n; //通过的瓷砖数 行数 列数 char map[MAX_ROW][MAX_COLUMN]; bool visited[MAX_ROW][MAX_COLUMN]; //记录访问标志的数组 //递归计算从(row,col)出发通过的瓷砖数 void search(int row, int col) { //边界条件 坐标在地图外,不可通行,已经访问过 则回溯 // 擦做者这里col>=n写错了,坑死了,找了2个小时 if (row < 0 || row >= n || col < 0 || col >= m || map[row][col] == 'W' || visited[row][col]) return; //cout<<row<<" "<<col<<" "<<sum<<endl; visited[row][col] = true; //设置当前坐标的标志位 ++sum; //通过的瓷砖数+1 //递归遍历当前坐标的四个相邻点 search(row , col-1); search(row, col+1); search(row-1, col); search(row+1 , col); } int main(){ while (cin >> m >> n) //输入列数和行数 { if(m==0 && n==0) break; int row, col; for (int i = 0; i < n; i++) { cin>> map[i]; //输入当前行的数据集 for (int j = 0; j < m; j++) { if (map[i][j] == '@') { row = i; col = j; } } } //cout<<row<<" "<<col<<endl; memset(visited,false,sizeof(visited)); sum = 0; search(row, col); cout << sum << endl; } return 0; }
题目描述[2]排序
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得全部的奇数位于数组的前半部分,全部的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。递归
v1 将原数组分割成两个子数组,而后再合并,时间复杂度O(n),空间复杂度较高。ci
void reOrderArray(vector<int> &array) { vector<int> odd;//odd numbers vector<int> eve;//even numbers for(int i=0;i<array.size();i++) { if(array[i]%2==0) odd.push_back(array[i]); else eve.push_back(array[i]); } array.clear(); array.insert(array.begin(),eve.begin(),eve.end()); array.insert(array.end(),odd.begin(),odd.end()); }
v2 将数组分为前半段(奇数)和后半段(混合)。用相似插入排序的思路把每次找到的奇数插入到前半段。等前半段增加结束就排好了。
用&1
判断奇数更高效
时间复杂度O(n^2),空间复杂度O(1)
void reOrderArray(vector<int> &v) { if(v.empty()) return; int lastodd=0; for(int i=0;i<v.size();i++) { if(v[i] & 1) { int t=v[i]; for(int j=i-1;j>=lastodd;j--) { v[j+1]=v[j]; } v[lastodd]=t; lastodd++; } } }