(二叉查找树)二叉查找树具有如下性质:每个节点的值都大于其左子树上所有节点的 值、小于其右子树上所有节点的值。试判断一棵树是否为二叉查找树。输入的第一行包含一个整数 n,表示这棵树有 n 个顶点,编号分别为 1, 2, ..., n,其中编号为 1 的为根结点。之后的第 i 行有三个数 value, left_child, right_child,分别表示该节点关键字的值、左子节点的编号、右子节点的编号;如果不存在左子节点或右子节点,则用 0 代替。输出 1 表示这棵树是二叉查找树,输出 0 则表示不是。
using namespace std;
const int SIZE = 100;
const int INFINITE = 1000000;
struct node {
int left_child, right_child, value;
};
node a[SIZE];
int is_bst(int root, int lower_bound, int upper_bound) {
int cur;
if (root == 0)
return 1;
cur = a[root].value;
if ((cur > lower_bound) && (【1】) && (is_bst(a[root].left_child, lower_bound, cur) == 1) && (is_bst(【2】, 【3】, 【4】) == 1))
return 1;
return 0;
}
int main(void) {
int i, n;
cin >> n;
for (i = 1; i <= n; i++)
cin >> a[i].value >> a[i].left_child >> a[i].right_child;
cout << is_bst(【5】, -INFINITE, INFINITE) << endl;
return 0;
}
思路:其实算法思路题目都讲清楚了,可形象化为下图:
就是根节点大于其左子树,小于其右子树,递归进行。需要注意的是【5】,这个需要填入的是根节点编号,题目说根节点是1,个人觉得a[1]也可以吧。
题目描述:
原始的Joseph问题的描述如下:有n个人围坐在一个圆桌周围,把这n个人依次编号为1,…,n。从编号是1的人开始报数,数到第m个人出列,然后从出列的下一个人重新开始报数,数到第m个人又出列,…,如此反复直到所有的人全部出列为止。比如当n=6,m=5的时候,出列的顺序依次是5,4,6,2,3,1。
现在的问题是:假设有k个好人和k个坏人。好人的编号的1到k,坏人的编号是k+1到2k。我们希望求出m的最小值,使得最先出列的k个人都是坏人。
输入:
仅有的一个数字是k(0 < k <14)。
输出:
使得最先出列的k个人都是坏人的m的最小值。
输入样例:
4
输出样例:
30
#include <stdio.h>
long k, m, begin;
int check(long remain){
long result = ( 【1】 ) % remain; //begin+m-1保证result最小值为1,因为最早出列的必定为k+1,故不需要一开始就考虑2k
if ( 【2】 ){
begin = result; return 1;
}
else return 0;
}
int main( ){
long i, find = 0;
scanf("%ld", &k);
m = k;
while( 【3】 ) {
find = 1; begin = 0;
for (i = 0; i < k; i++)
if (!check( 【4】 )){
find = 0; break;
}
m++;
}
printf("%ld\n", 【5】 );
return 0;
}
算法思想:
首先检查第m个人是否是坏人(设置从第一个开始数,如果是坏人则取出,从下一个位继续数,但去除一位了,所以下一位就是从原来的位置开始数,begin为设置从第几位开始数),循环查找,若k人中遍历到好人则m=m+1。遍历结束全是坏人则跳出循环。
排列数)输入两个正整数n,m(1<n<20, 1<m<n),在1~n中任取m个数,按字典序从小到大输出所有这样的排列。例如:
输入:3 2
输出:1 2
1 3
2 1
2 3
3 1
3 2
这题要注意按字典从小到大输出所有可能的排列题干要看清楚,不是输出的排列要按从小到大排!!
#include <iostream>
#include <cstring>
using namespace std;
const int SIZE = 25;
bool used[SIZE];
int data[SIZE];
int n, m, i, j, k;
bool flag;
int main( ) {
cin >> n >> m;
memset(used, false, sizeof(used));
for (i = 1; i <= m; i++) {
data[i] = i;
used[i] = true;
}
flag = true;
while (flag) {
for (i = 1; i <= m - 1; i++) cout << data[i] << " ";
cout << data[m] << endl;
flag = false;
for (i = m; i >= 1; i--) {
used[data[i]] = false;
for (j = data[i] + 1; j <= n; j++)
if (!used[j]) {
used[j] = true;
data[i] = j;
flag = true;
break;
}
if (flag) {
for (k = i + 1; k <= m; k++)
for (j = 1; j <= n;
j++)
if (!used[j]) {
data[k] = j;
used[j] = true;
break;
}
break;
}
}
}
return 0;
}
判断质数
题目描述
给出一个正整数,判断这个数是否是质数。
输入:
一个正整数n(1 ≤ n ≤ 10000)。
输出:
如果n是质数,输出"YES";否则,输出"NO"。
输入样例:
10
输出样例:
NO
程序:\
#include <stdio.h>
int main( ) {
int 【1】;
scanf("%d", &n);
if (n == 2) puts( 【2】);
else if ( 【3】|| n % 2 == 0) puts("NO");
else
{
i = 3;
while (i * i <= n) {
if ( 【4】)
{
puts("NO");
return 0;
}
i = i + 2;
}
puts("YES");
}
return 0;
}
算法思想:
1不是质数,n从2开始,质数只能被1和其本身整除,能被2整除的断然不是质数。当n>i^2(i>=3,i=i+2)时,如果能整除i则也不是质数。
(序列重排)全局数组变量 a 定义如下:
const int SIZE = 100;
int a[SIZE], n;
它记录着一个长度为 n 的序列 a[1], a[2], ..., a[n]。
现在需要一个函数,以整数 p (1 ≤ p ≤ n)为参数,实现如下功能:将序列 a 的前 p
个数与后 n – p 个数对调,且不改变这 p 个数(或 n – p 个数)之间的相对位置。例如,
长度为 5 的序列 1, 2, 3, 4, 5,当 p = 2 时重排结果为 3, 4, 5, 1, 2。
有一种朴素的算法可以实现这一需求,其时间复杂度为 O(n)、空间复杂度为 O(n):
void swap1(int p) { int i, j, b[SIZE];
for (i = 1; i <= p; i++)
b[【1】] = a[i];
for (i = p + 1; i <= n; i++)
b[i - p] =【2】
for (i = 1; i <=【3】; i++)
a[i] = b[i];
}
我们也可以用时间换空间,使用时间复杂度为 O(n 2 )、空间复杂度为 O(1)的算法:
void swap2(int p) {
int i, j, temp;
for (i = p + 1; i <= n; i++) {
temp = a[i];
for (j = i; j >=【4】; j--)
a[j] = a[j - 1];
【5】= temp;
}
}
两数交换较为简单,就不做介绍了。