int a[1009], isMin = 1, isMax = 1; //数组a存储堆(完全二叉树),第一个节点的索引为1
//isMin标识是否为小顶堆 isMax标识是否为大顶堆
for (int i = 2; i <= n; i++) { //和父结点比较value
if (a[i/2] > a[i]) isMin = 0;
if (a[i/2] < a[i]) isMax = 0;
}
if (isMin == 1)
printf("Min Heap");
else
printf("%s", isMax == 1 ? "Max Heap" : "Not Heap");
//若isMin和isMax都为1,则不是堆
vector<int> v; //用于存储深度遍历从根到叶子结点的路径
void dfs(int index) { //此处遍历方式为右->根->左
if (index * 2 > n && index * 2 + 1 > n) { //该结点为叶子结点
if (index <= n) {
for (int i = 0; i < v.size(); i++)
printf("%d%s", v[i], i != v.size() - 1 ? " " : "\n");
}
} else {
if(index * 2 + 1<=n){
v.push_back(a[index * 2 + 1]);
dfs(index * 2 + 1);
v.pop_back();
}
if(index * 2 <=n) {
v.push_back(a[index * 2]);
dfs(index * 2);
v.pop_back();
}
}
}
bool isPrime(int n) {
if (n == 0 || n == 1) return false;
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
已知某个树的根结点,若a和b在根结点的左边,则a和b的最近公共祖先在当前子树根结点的左子树寻找,如果a和b在当前子树根结点的两边,在当前子树的根结点就是a和b的最近公共祖先,如果a和b在当前子树根结点的右边,则a和b的最近公共祖先就在当前子树的右子树寻找。
map<int, int> pos; //记录中序遍历中每个结点的位置以便比较和根结点的位置关系
vector<int> in, pre; //记录中序遍历和先序遍历
void lca(int inl, int inr, int preRoot, int a, int b) {
if (inl > inr) return;
//找出当前根结点和两个结点的位置,然后进行比较
int inRoot = pos[pre[preRoot]], aIn = pos[a], bIn = pos[b];
if (aIn < inRoot && bIn < inRoot)
lca(inl, inRoot-1, preRoot+1, a, b);
else if ((aIn < inRoot && bIn > inRoot) || (aIn > inRoot && bIn < inRoot))
printf("LCA of %d and %d is %d.\n", a, b, in[inRoot]);
else if (aIn > inRoot && bIn > inRoot)
lca(inRoot+1, inr, preRoot+1+(inRoot-inl), a, b);
else if (aIn == inRoot)
printf("%d is an ancestor of %d.\n", a, b);
else if (bIn == inRoot)
printf("%d is an ancestor of %d.\n", b, a);
}
对于二叉搜索树的最低公共祖先则更加容易。二叉搜索树具有显著的特点,即根结点的值大于等于左子树结点的值,小于右子树结点的值。所以只需要知道先序遍历序列,然后从前往后查找某一个结点的值位于两个给定的结点的值之间,则必为最低公共祖先。因为先序遍历的特点,所以从前向后遍历每个结点等同于从上到下对每个根结点进行测试(即先序遍历的特点)。
vector<int> pre(n); //存储先序遍历序列
for (int i = 0; i < m; i++) {
scanf("%d %d", &u, &v);
for(int j = 0; j < n; j++) {
a = pre[j];
if ((a >= u && a <= v) || (a >= v && a <= u)) break;
}
if (mp[u] == false && mp[v] == false)
printf("ERROR: %d and %d are not found.\n", u, v);
else if (mp[u] == false || mp[v] == false)
printf("ERROR: %d is not found.\n", mp[u] == false ? u : v);
else if (a == u || a == v)
printf("%d is an ancestor of %d.\n", a, a == u ? v : u);
else
printf("LCA of %d and %d is %d.\n", u, v, a);
}
如果给出的路径存在某两个连续的点不可达或者第一个结点和最后一个结点不同或者这个路径没有访问过图中所有的点,那么它就不是一个环路(flag = 0)~如果满足了环路的条件,那么再判断这个环路路否是简单旅环路,即是否访问过n+1个结点(源点访问两次)
vector<int> list; //存储走过的结点
set<int> s;
//用以记录访问过的结点,利用了set元素不重复的性质,最后查看set元素个数即可知道是否所有结点都访问过
for(int j=0;j<num-1;j++){
if(e[list[j]][list[j+1]]==0){ 若存在结点之间不可达则不是环路
flag=0;
}
sum += e[list[j]][list[j+1]]; //记录边权值加和
}
if(flag==0){
printf("Path %d: NA (Not a TS cycle)\n",k+1);
}else if(s.size()!=n || list[0]!=list[num-1]) //没有全部走过一遍或者最后一个结点和初始结点不一样
{
printf("Path %d: %d (Not a TS cycle)\n",k+1,sum);
}
else if(num != n+1) //全部走过了一遍,但是多走了若干个结点
{
printf("Path %d: %d (TS cycle)\n",k+1,sum);
if(sum < ans){ //找出最短路径的边权值之和和路径的编号
ans = sum;
ansid = k+1;
}
}else{
printf("Path %d: %d (TS simple cycle)\n",k+1,sum);
if(sum < ans){
ans = sum;
ansid = k+1;
}
}
一个具有n个节点的完全二叉树,其叶子节点的个数n0为: n/2 向上取整,或者(n+1)/2 向下取整。
推导:n0+n1+n2 = n , n1+2n2=n-1 又n1=0或1
当n=1时(n为偶数),n0 = n/2 当n=0时(n为奇数),n0 = n+1/2
综上所述 叶子节点的个数n0为: n/2 向上取整 非叶子结点个数为n/2 向下取整
//完全二叉树的层次遍历就是堆的静态存储结构
//堆的后序遍历,此处堆的存储索引从0开始
//左子树根结点的索引为2*i+1,右子树根结点的索引为2*i+2
void postOrder(int index) {
if (index >= n) return;
postOrder(index * 2 + 1);
postOrder(index * 2 + 2);
printf("%d%s", v[index], index == 0 ? "\n" : " ");
}
//此处判断是否为堆的思路稍微不同,判断每个结点的左右子树的根结点与当前结点的值的关系。
int flag = v[0] > v[1] ? 1 : -1; //根据根结点和左孩子的大小关系判断为大(小)顶堆
for (int j = 0; j <= (n-1) / 2; j++) { //遍历所有非叶子结点个数
int left = j * 2 + 1, right = j * 2 + 2;
if (flag == 1 && (v[j] < v[left] || (right < n && v[j] <v[right])))
flag = 0;
if (flag == -1 && (v[j] > v[left] || (right < n && v[j] >v[right])))
flag = 0;
}
if (flag == 0) printf("Not Heap\n");
else printf("%s Heap\n", flag == 1 ? "Max" : "Min");
}
vector<int> v[1010]; //邻接表
int in[1010]; //入度数组
int flag=0; //flag用于标识是否为第一个输出
for(int i=0;i<k;i++){
vector<int> tin(in,in+n+1); //创建入度数组的副本
int judge=1; //标识是否为拓扑序列
for(int j=0;j<n;j++){
scanf("%d",&a); //输入结点进行判断
if(tin[a]!=0) judge = 0; //输出结点的入度不为0,表示不为拓扑序列
for(int it : v[a]) tin[it]--;
}
if(judge==1) continue; //为拓扑序列不输出,不为拓扑序列输出编号
printf("%s%d",flag==1?" ":"",i); //flag==0表示第一次输出
flag = 1;
}
bool isprime(int n) {
for (int i = 2; i * i <= n; i++)
if (n % i == 0) return false;
return true;
}
//size为哈希表容量大小,找寻大于等于size的最小质数做哈希函数中的tsize[H(key) = key % tsize]
while(!isprime(tsize)) tsize++;
//将数据插入
vector<int> v(tsize);
for (int i = 0; i < n; i++) {
scanf("%d", &a);
int flag = 0;
for (int j = 0; j < tsize; j++) {
int pos = (a + j * j) % tsize; //平方探测的j为 0 ~ tsize-1
if (v[pos] == 0) {
v[pos] = a;
flag = 1;
break;
}
}
if (!flag) printf("%d cannot be inserted.\n", a);
}
//查找
int ans = 0; //记录查找次数
for (int i = 0; i < m; i++) {
scanf("%d", &a);
for (int j = 0; j <= tsize; j++) { //查找时j为 0 ~ tsize
ans++;
int pos = (a + j * j) % tsize;
if (v[pos] == a || v[pos] == 0) break;
}
}