一、strcpy和memcpy的区别。
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符”\0”才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy
memcpy的实现
要注意,内存重叠的情况,比如
char test[]=”abcdefghi”;
memcpy(test+3,test,6);
如果从头向尾复制,结果就是abcabcabc,正确结果应该是abcabcdef。所以像这种情况应该从尾向头复制
void memcpydiy(char *dest,const char *scr,int len)
{
if (dest == NULL || scr == NULL)
return;
char *pdest = dest;
char *pscr = (char *)scr;
if ((scr < dest) && (dest < scr + len)) //重叠,从尾部开始复制
{
pdest = pdest + len - 1;
pscr = pscr + len - 1;
while (len--)
{
*pdest-- = *pscr--;
}
}
else
{
while (len--)
{
*pdest++ = *pscr++;
}
}
}
二、二叉搜索树
节点的数据结构:
struct node
{
int value;
node* left;
node* right;
};
方法1(错误示范:自己踩的坑)
首先BST是一个递归定义:这样我们首先想到用递归的方式进行判断:
//对于每个节点,检测它的左孩子节点是否小于它,且右孩子节点是否大于它。
bool isBST(node* root)
{
if (root == NULL)
return true;
//如果左孩子大于根节点,则不是BST
if (root->left != NULL && root->left->key> root->key)
return false;
//如果右孩子节点小于根节点,则不是BST
if (root->right != NULL && root->right->key < root->key)
return false;
//递归的判断
if (!isBST(root->left) || !isBST(root->right))
return false;
//BST
return true;
}
如:
方法2
根据最基础的定义,我们在判断每棵子树的时候返回左子树的最大值小于当前节点值,同时右子树的最小值大于当前节点值,是的,这样会出现某些节点进行多次判断,当然我们可以通过添加数组结构来保存中间结果加快计算
二叉树的最大值出现在最右侧的位置,最小值出现在最左侧的部分
int maxValue(node* root)
{
if(root == NULL)
return INT_MAX
while(root -> right)
root = root -> right;
return root -> value;
}
int minValue(node* root)
{
if(root == NULL)
return INT_MIN
while(root -> left)
root = root -> left;
return root -> value;
}
bool isBST(node* root )
{
if (root == NULL)
return true;
//如果左子树最大值大于根节点,则返回false
if (root->left != NULL && maxValue(root->left) > node->value)
return false;
//如果右子树最小值小于根节点,则返回false
if (root->right != NULL && minValue(root->right) < node->value)
return false;
//递归判断
if (!isBST(root->left) || !isBST(root->right))
return false;
return true;
}
方法3
我们知道,二叉搜索树的中序遍历是一个递增序列,所以我们只需要把这个中序遍历保存下来,然后判断这是个递增序列即可:
void LDR(node * root, vector<int>& inorder)
{
if(root == NULL)
return;
LDR(root -> left);
inorder.push_back(root -> value);
LDR(root -> right);
}
bool isBST(node* root)
{
vector<int> inorder;
LDR(root);
for(int i = 1; i < inorder.size(); ++i)
if(inorder[i - 1] >= inorder[i])
return false;
return true;
}
方法4
其实用的还是之前的中序遍历的方法,但我们实际上也看到了,在方法3中判断合法的方法也是在把现在的值跟前一个值进行比较
//保存之前访问过的节点的值,判断当前访问的小于之前保存的值
int lastVisited = INT_MIN;
bool isBST(node * root)
{
if(root == NULL)
return true;
//判断左子树
if(!LDR(root -> left))
return false;
if(root -> value <= lastVisited)
return false;
lastVisited = root -> value;
//判断右子树
if(!LDR(root -> right))
return false;
return true;
}
方法5
这里其实用的是是前序遍历,当前节点的值是左子树的最大值,同时是右子树的最小值,所以我们接下来进行递归判断即可
bool isBST(node *root, int maxVal, int minVal)
{
if (root == NULL)
return true;
if (root->val < minVal || root->val >= maxVal)
return false;
if (!preOrder(root->left, root->val, minVal) || !preOrder(root->right, maxVal, root->val))
return false;
return true;
}
isBST(root, INT_MAX, INT_MIN);
三、四则运算
思路:
使用两个栈,一个栈用来保存当前操作符,一个栈用来保存操作数。
从前往后遍历字符串:
当遇到数字时直接压入操作数栈;
当遇到正括号 (、[、{ 时直接压入操作符栈;
当遇到乘号或者除号时,判断前一个操作符(即操作符栈栈顶元素)是否为除号,如果前一个操作符为除号则先从操作数栈弹出栈顶两个元素计算除号,除法结果压入操作数栈,然后从操作符栈弹出除法操作符;
当遇到加号或者减号时,如果这个加号或减号是输入字符串的第一个字符时,或者字符串前一个字符为正括号 (、[、{ 时,在操作数栈栈顶压入一个 0, 如果不是这种情况再继续考虑,如果前一个操作符(即操作符栈顶元素)是否为乘号或者除号或者减号,如果是乘号或者除号,就一直从操作数栈弹出两个元素进行乘法或者除法运算,结果压入操作数栈,一直进行到前一个操作符不再是乘号或者除号为止,如果前一个操作符为减号,则也先从操作数栈弹出两个元素进行减法运算,结果压入操作数栈;
当遇到反括号 )、]、} 时, 从操作数栈弹出两个元素,从操作符栈弹出一个操作符,进行算术运算,指导操作符栈栈顶元素为对应的正括号 (、[、{ 时停止进行算术运算,并将正括号从操作符栈弹出。
当输入字符串遍历结束以后,如果操作符栈不为空,则操作数栈弹出两个元素,从操作符弹出一个操作符,进行算术运算,直到操作符栈为空,这个过程相当于最后的表达式从后往前计算,因为有前面的判断逻辑保证,逆序计算不会影响结果。
上述整个过程结束后,操作符栈为空,操作数栈中只剩下整个表达式计算的结果值,返回该结果,弹出栈即可。
代码:
#include <iostream>
#include <string>
#include <stack>
using namespace std;
double calculate(string s)
{
stack<double> num;
stack<char> op;
string temp = "";
for(int i = 0; i < s.length(); i++)
{
if(s[i] >= '0' && s[i] <= '9')
{
temp += s[i];
}
if((s[i] < '0' || s[i] > '9') && temp != "")
{
num.push(atoi(temp.c_str()));
temp = "";
}
if(s[i] == '(' || s[i] == '[' || s[i] == '{')
{
op.push(s[i]);
}
if(s[i] == '*' || s[i] == '/')
{
if(!op.empty())
{
char lastop = op.top();
if(lastop == '/')
{
double secondnum = num.top();
num.pop();
double firstnum = num.top();
num.pop();
num.push(firstnum*1.0/secondnum);
op.pop();
}
}
op.push(s[i]);
}
if(s[i] == '+' || s[i] == '-')
{
if(i == 0 || s[i-1] == '(' || s[i-1] == '[' || s[i-1] == '{')
{
num.push(0);
}
if(!op.empty())
{
char lastop = op.top();
while(!op.empty() && (lastop == '*' || lastop == '/'))
{
double secondnum = num.top();
num.pop();
double firstnum = num.top();
num.pop();
if(lastop == '*')
num.push(firstnum*secondnum);
else if(lastop == '/')
num.push(firstnum*1.0/secondnum);
op.pop();
if(!op.empty())
lastop = op.top();
}
if(lastop == '-')
{
double secondnum = num.top();
num.pop();
double firstnum = num.top();
num.pop();
num.push(firstnum-secondnum);
op.pop();
}
}
op.push(s[i]);
}
if(s[i] == ')')
{
if(!op.empty())
{
char lastop = op.top();
while(!op.empty() && lastop != '(')
{
double secondnum = num.top();
num.pop();
double firstnum = num.top();
num.pop();
switch(lastop)
{
case '+':
num.push(firstnum+secondnum);
break;
case '-':
num.push(firstnum-secondnum);
break;
case '*':
num.push(firstnum*secondnum);
break;
case '/':
num.push(firstnum*1.0/secondnum);
break;
}
op.pop();
if(!op.empty())
lastop = op.top();
}
if(lastop == '(')
op.pop();
}
}
if(s[i] == ']')
{
if(!op.empty())
{
char lastop = op.top();
while(!op.empty() && lastop != '[')
{
double secondnum = num.top();
num.pop();
double firstnum = num.top();
num.pop();
switch(lastop)
{
case '+':
num.push(firstnum+secondnum);
break;
case '-':
num.push(firstnum-secondnum);
break;
case '*':
num.push(firstnum*secondnum);
break;
case '/':
num.push(firstnum*1.0/secondnum);
break;
}
op.pop();
if(!op.empty())
lastop = op.top();
}
if(lastop == '[')
op.pop();
}
}
if(s[i] == '}')
{
if(!op.empty())
{
char lastop = op.top();
while(!op.empty() && lastop != '{')
{
double secondnum = num.top();
num.pop();
double firstnum = num.top();
num.pop();
switch(lastop)
{
case '+':
num.push(firstnum+secondnum);
break;
case '-':
num.push(firstnum-secondnum);
break;
case '*':
num.push(firstnum*secondnum);
break;
case '/':
num.push(firstnum*1.0/secondnum);
break;
}
op.pop();
if(!op.empty())
lastop = op.top();
}
if(lastop == '{')
op.pop();
}
}
}
if(temp != "")
num.push(atoi(temp.c_str()));
while(!op.empty())
{
char lastop = op.top();
double secondnum = num.top();
num.pop();
double firstnum = num.top();
num.pop();
switch(lastop)
{
case '+':
num.push(firstnum+secondnum);
break;
case '-':
num.push(firstnum-secondnum);
break;
case '*':
num.push(firstnum*secondnum);
break;
case '/':
num.push(firstnum*1.0/secondnum);
break;
}
op.pop();
}
if(num.empty())
return 0;
double value = num.top();
num.pop();
return value;
}
void test1()
{
string s;
while(cin >> s)
{
cout << calculate(s) << endl;
}
}
int main()
{
test1();
return 0;
}