03-树1. List Leaves (25)
Given a tree, you are supposed to list all the leaves in the order of top down, and left to right.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (<=10) which is the total number of nodes in the tree -- and hence the nodes are numbered from 0 to N-1. Then N lines follow, each corresponds to a node, and gives the indices of the left and right children of the node. If the child does not exist, a "-" will be put at the position. Any pair of children are separated by a space.
Output Specification:
For each test case, print in one line all the leaves' indices in the order of top down, and left to right. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.
Sample Input:
8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6
Sample Output:
4 1 5
/* 思路:需要动态的建立二叉树,然后层次遍历输出叶结点,但是有一个问题是要防止指针丢失,因此我在程序中用一个数组维护各个结点的指针;最后树建完以后,还要想办法找到数根,我采取的措施是:遍历维护结点指针的数组,对其左、右结点值求和,这样除了根结点以外,所有结点都被计入总和中了,利用这一信息便可以找到根节点的位置。 */ #include<stdio.h> #include<string.h> #include<malloc.h>
#define MAXN 10 typedef struct tnode { int data; struct tnode * left; struct tnode * right; }TNODE, *PTNODE; typedef struct qnode { PTNODE data; struct qnode * next; }QNODE, *PQNODE; typedef struct queue { PQNODE front; PQNODE rear; }QUEUE, *PQUEUE; PQUEUE MakeQueue(); void Add(PQUEUE, PTNODE pTNode); PTNODE Delete(PQUEUE pQ); int IsEmpty(PQUEUE pQ); PTNODE arr[MAXN+1]; void Dispose(int i, char left, char right); PTNODE FindRoot(int n); // n个节点中找根节点
int main(void) { int n, i, isFirst; char left, right; PTNODE root, head; scanf("%d", &n); memset(arr, 0, sizeof(arr)); for(i = 0; i < n; i++) { scanf(" %c %c", &left, &right); Dispose(i, left, right); } root = FindRoot(n); // printf("%d\n", root->data); // test // 层次遍历
PQUEUE pQ = MakeQueue(); Add(pQ, root); isFirst = 1; while(!IsEmpty(pQ)) { head = Delete(pQ); if(head->left == NULL && head->right == NULL) { if(isFirst) isFirst = 0; else putchar(' '); printf("%d", head->data); } Add(pQ, head->left); Add(pQ, head->right); } return 0; } void Dispose(int i, char left, char right) // 当前节点,左、右节点哪个没有建哪个
{ if(arr[i] == NULL) arr[i] = (PTNODE)malloc(sizeof(TNODE)); arr[i]->data = i; if(left == '-') arr[i]->left = NULL; else { if(arr[left-'0'] == NULL) arr[left-'0'] = (PTNODE)malloc(sizeof(TNODE)); arr[i]->left = arr[left-'0']; } if(right == '-') arr[i]->right = NULL; else { if(arr[right-'0'] == NULL) arr[right-'0'] = (PTNODE)malloc(sizeof(TNODE)); arr[i]->right = arr[right-'0']; } return; } PTNODE FindRoot(int n) { int i, sum = 0; for(i = 0; i < n; i++) { if(arr[i]->left) sum += arr[i]->left->data; if(arr[i]->right) sum += arr[i]->right->data; } return arr[n*(n-1)/2 - sum]; // 这里用了一点技巧
} PQUEUE MakeQueue() { PQUEUE pQ = malloc(sizeof(QUEUE)); pQ->front = pQ->rear = NULL; return pQ; } void Add(PQUEUE pQ, PTNODE pTNode) { if(pTNode == NULL) return; PQNODE p = (PQNODE)malloc(sizeof(QNODE)); // 注意正规的程序应该检查申请堆内存是否成功
p->data = pTNode; p->next = NULL; if(pQ->front == NULL) pQ->front = pQ->rear = p; else { pQ->rear->next = p; pQ->rear = p; } } PTNODE Delete(PQUEUE pQ) { PTNODE p; PQNODE pTemp; if(pQ->front == NULL) return NULL; if(pQ->rear == pQ->front) pQ->rear = NULL; p = pQ->front->data; pTemp = pQ->front; pQ->front = pQ->front->next; free(pTemp); return p; } int IsEmpty(PQUEUE pQ) { return pQ->front == NULL ? 1 : 0; }
03-树2. Tree Traversals Again (25)
An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example, suppose that when a 6-node binary tree (with the keys numbered from 1 to 6) is traversed, the stack operations are: push(1); push(2); push(3); pop(); pop(); push(4); pop(); pop(); push(5); push(6); pop(); pop(). Then a unique binary tree (shown in Figure 1) can be generated from this sequence of operations. Your task is to give the postorder traversal sequence of this tree.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=30) which is the total number of nodes in a tree (and hence the nodes are numbered from 1 to N). Then 2N lines follow, each describes a stack operation in the format: "Push X" where X is the index of the node being pushed onto the stack; or "Pop" meaning to pop one node from the stack.
Output Specification:
For each test case, print the postorder traversal sequence of the corresponding tree in one line. A solution is guaranteed to exist. All the numbers must be separated by exactly one space, and there must be no extra space at the end of the line.
Sample Input:
6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop
Sample Output:
3 4 2 6 5 1
/* 思路:先用一个真实的栈模拟输入,据此中序建树,然后执行后序遍历输出结果即可 */ #include<stdio.h> #include<malloc.h> typedef struct tnode { int data; struct tnode * left; struct tnode * right; }TNODE, *PTNODE; typedef struct snode { PTNODE data; struct snode * next; }SNODE, *PSNODE; PSNODE MakeStack(); void Push(PSNODE * pS, PTNODE data); PTNODE Pop(PSNODE * pS); int IsEmpty(PSNODE pS); PTNODE Dispose(PTNODE * lastPTNode, int numberNode); void PostOrderTraverse(PTNODE pTNode); int first = 1; // 后序遍历中是否是第一个输出节点的标记
int main(void) { int n, numberNode; PTNODE root, lastPTNode, currentPTNode; PSNODE pS; char str[10]; pS = MakeStack(); scanf("%d", &n); scanf("%s%d", str, &numberNode); // 建立数根root,并将之压栈
root = lastPTNode = (PTNODE)malloc(sizeof(TNODE)); root->data = numberNode; root->left = root->right = NULL; Push(&pS, root); while(scanf("%s", str) != EOF) { if(str[1] == 'u') { scanf("%d", &numberNode); currentPTNode = Dispose(&lastPTNode, numberNode); Push(&pS, currentPTNode); } else if(str[1] == 'o') { lastPTNode = Pop(&pS); } } PostOrderTraverse(root); return 0; } PSNODE MakeStack() { PSNODE p = (PSNODE)malloc(sizeof(SNODE)); p->data = NULL; return p; } void Push(PSNODE * pS, PTNODE data) { PSNODE p = (PSNODE)malloc(sizeof(SNODE)); p->data = data; p->next = *pS; *pS = p; } PTNODE Pop(PSNODE * pS) { PTNODE data; PSNODE pTemp; if(IsEmpty(*pS)) return NULL; data = (*pS)->data; // 优先级!
pTemp = *pS; *pS = (*pS)->next; free(pTemp); return data; } int IsEmpty(PSNODE pS) { return pS == NULL ? 1 : 0; } PTNODE Dispose(PTNODE * lastPTNode, int numberNode) { PTNODE pTemp; pTemp = (PTNODE)malloc(sizeof(TNODE)); pTemp->data = numberNode; pTemp->left = pTemp->right = NULL; if((*lastPTNode)->left == NULL) // 注意运算符优先级
(*lastPTNode)->left = pTemp; else (*lastPTNode)->right = pTemp; *lastPTNode = pTemp; return pTemp; } void PostOrderTraverse(PTNODE pTNode) { if(pTNode) { PostOrderTraverse(pTNode->left); PostOrderTraverse(pTNode->right); if(first) first = 0; else putchar(' '); printf("%d", pTNode->data); } return ; }
04-树3. Root of AVL Tree (25)
An AVL tree is a self-balancing binary search tree. In an AVL tree, the heights of the two child subtrees of any node differ by at most one; if at any time they differ by more than one, rebalancing is done to restore this property. Figures 1-4 illustrate the rotation rules.
Now given a sequence of insertions, you are supposed to tell the root of the resulting AVL tree.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=20) which is the total number of keys to be inserted. Then N distinct integer keys are given in the next line. All the numbers in a line are separated by a space.
Output Specification:
For each test case, print ythe root of the resulting AVL tree in one line.
Sample Input 1:
5
88 70 61 96 120
Sample Output 1:
70
Sample Input 2:
7
88 70 61 96 120 90 65
Sample Output 2:
88
// 很直白的考察AVL建树,不过多赘述了~
#include<stdio.h> #include<malloc.h> typedef struct node { int data; struct node * left; struct node * right; int height; }NODE, *PNODE; PNODE Insert(PNODE pNode, int data); int Height(PNODE pNode); int MaxHeight(PNODE pLeft, PNODE pRight); PNODE SingleRightRotation(PNODE A); PNODE DoubleRightLeftRotation(PNODE A); PNODE SingleLeftRotation(PNODE A); PNODE DoubleLeftRightRotation(PNODE A); int main(void) { int n, data; PNODE avlRoot; scanf("%d", &n); scanf("%d", &data); avlRoot = Insert(NULL, data); n--; while(n--) { scanf("%d", &data); avlRoot = Insert(avlRoot, data); } printf("%d\n", avlRoot->data); return 0; } PNODE Insert(PNODE pRoot, int data) { if(pRoot == NULL) { pRoot = (PNODE)malloc(sizeof(NODE)); pRoot->data = data; pRoot->left = pRoot->right = NULL; pRoot->height = 0; } else if(data > pRoot->data) { pRoot->right = Insert(pRoot->right, data); // 判断是否要旋转
if(Height(pRoot->right) - Height(pRoot->left) == 2) { // 判断是右右旋转还是右左旋转
if(data > pRoot->right->data) // 右右旋转
return SingleRightRotation(pRoot); // 旋转完了返回修正部分的根节点,并将其返回给上一次调用它的父节点
else // 右左旋转
return DoubleRightLeftRotation(pRoot); } } else if(data < pRoot->data) { pRoot->left = Insert(pRoot->left, data); if(Height(pRoot->left) - Height(pRoot->right) == 2) { if(data < pRoot->left->data) // 左左旋转
return SingleLeftRotation(pRoot); else // 左右旋转
return DoubleLeftRightRotation(pRoot); } } pRoot->height = MaxHeight(pRoot->left, pRoot->right) + 1; return pRoot; } int Height(PNODE pNode) { if(pNode == NULL) return -1; else
return pNode->height; } int MaxHeight(PNODE pLeft, PNODE pRight) { if(pLeft == NULL && pRight == NULL) return -1; else if(pLeft == NULL) return pRight->height; else if(pRight == NULL) return pLeft->height; else if(pLeft->height > pRight->height) return pLeft->height; else
return pRight->height; } PNODE SingleRightRotation(PNODE A) // 右右旋转,返回旋转部分的根节点
{ PNODE B = A->right; A->right = B->left; B->left = A; /* 可以代替下面两行: A->height = Height(A->left) + 1; // 这里没有通过比较更新A的高度,因为我觉得其高度不会变,因为BL不会大于AL(否则在之前它们就不平衡了),更具体的原因可以在我之前的博文"AVL树旋转特性"中找到 B->height = A->height + 1; // 与上述理由类似 */ A->height = MaxHeight(A->left, A->right) + 1; B->height = MaxHeight(B->left, A) + 1; return B; } PNODE DoubleRightLeftRotation(PNODE A) { // 注意到只需要左左旋转然后右右旋转,两者组合起来就是右左旋转
A->right = SingleLeftRotation(A->right); // 以B为根进行左左旋转
return SingleRightRotation(A); // 以A为根进行右右旋转
} PNODE SingleLeftRotation(PNODE A) { PNODE B = A->left; A->left = B->right; B->right = A; A->height = MaxHeight(A->left, A->right) + 1; B->height = MaxHeight(B->left, A) + 1; return B; } PNODE DoubleLeftRightRotation(PNODE A) { A->left = SingleRightRotation(A->left); return SingleLeftRotation(A); }
04-树4. Search in a Binary Search Tree (25)
To search a key in a binary search tree, we start from the root and move all the way down, choosing branches according to the comparison results of the keys. The searching path corresponds to a sequence of keys. For example, following {1, 4, 2, 3} we can find 3 from a binary search tree with 1 as its root. But {2, 4, 1, 3} is not such a path since 1 is in the right subtree of the root 2, which breaks the rule for a binary search tree. Now given a sequence of keys, you are supposed to tell whether or not it indeed correspnds to a searching path in a binary search tree.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N and M (<=100) which are the total number of sequences, and the size of each sequence, respectively. Then N lines follow, each gives a sequence of keys. It is assumed that the keys are numbered from 1 to M.
Output Specification:
For each sequence, print in a line "YES" if the sequence does correspnd to a searching path in a binary search tree, or "NO" if not.
Sample Input:
3 4
1 4 2 3
2 4 1 3
3 2 4 1
Sample Output:
YES
NO
NO
/* 思路:按照给定的数据建树,只要当前结点是上一个节点的孩子,则继续这个过程,如果到达输入末尾,则说明路径存在,否则路径不存在,PS:由于这个思路执行起来更快,所以选择了它,其实解决这个问题的时候,我首先想到的办法是:根据输入建树,然后最后输入的那个结点,如果查找的过程中经过了所有结点,那么路径存在,否则路径不存在 */ #include<stdio.h> #include<malloc.h> typedef struct node { int data; struct node * left; struct node * right; }NODE, *PNODE; PNODE Insert(PNODE root, int data); // 返回插入的节点,如果节点已经存在,返回空指针
PNODE Find(PNODE root, int data); void Delete(PNODE root); int main(void) { int flag; // 当前节点是否是上一个节点的孩子的标记变量
PNODE curNode, preNode, root; int i, n, m, data; scanf("%d%d", &n, &m); root = NULL; while(n--) { Delete(root); // 删除上一次建的树
scanf("%d", &data); root = NULL; // 注意一定要置空,否则用上次释放的root做根会出现访问非法的问题
root = Insert(root, data); // 首先建立根节点
preNode = root; flag = 1; for(i = 1; i < m; i++) { scanf("%d", &data); if(flag) { Insert(root, data); curNode = Find(root, data); if(preNode->left != curNode && preNode->right != curNode) flag = 0; preNode = curNode; } } if(flag) printf("YES\n"); else printf("NO\n"); } return 0; } PNODE Insert(PNODE root, int data) { if(root == NULL) { PNODE pNode = (PNODE)malloc(sizeof(NODE)); pNode->data = data; pNode->left = pNode->right = NULL; return pNode; } if(data > root->data) root->right = Insert(root->right, data); // 由于插入的时候需要记住它的父节点,因此这里有赋值语句
else if(data < root->data) root->left = Insert(root->left, data); else // 数据相等的话直接退出,因为二叉搜索树不允许有相同的键值
return NULL; return root; } PNODE Find(PNODE root, int data) { if(root == NULL) return NULL; if(data > root->data) return Find(root->right, data); else if(data < root->data) return Find(root->left, data); else
return root; } void Delete(PNODE root) { if(root == NULL) return ; Delete(root->right); // 删除右子树
root->right = NULL; // 注意到这里需要赋值语句用来修改节点的右指针
Delete(root->left); root->left = NULL; free(root); // 释放根节点的空间
}
04-树5. Complete Binary Search Tree (30)
A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:
The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than or equal to the node's key.
Both the left and right subtrees must also be binary search trees.
A Complete Binary Tree (CBT) is a tree that is completely filled, with the possible exception of the bottom level, which is filled from left to right.
Now given a sequence of distinct non-negative integer keys, a unique BST can be constructed if it is required that the tree must also be a CBT. You are supposed to output the level order traversal sequence of this BST.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (<=1000). Then N distinct non-negative integer keys are given in the next line. All the numbers in a line are separated by a space and are no greater than 2000.
Output Specification:
For each test case, print in one line the level order traversal sequence of the corresponding complete binary search tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.
Sample Input:
10
1 2 3 4 5 6 7 8 9 0
Sample Output:
6 3 8 1 5 7 9 0 2 4
/* 首先,这个题真的很有意思:~ 思路: 把输入数据放入数组冒泡排序 用类似层次遍历的方式建立一颗有N个节点的完全二叉树,每次malloc一个节点num加一 采用中序遍历的方式用一个全局变量将所用的节点标号 层次遍历,根据标号(对应数组下标)放入数值(为了更好的达到练习效果,我直接先序了),同时输出 */ #include<stdio.h> #include<malloc.h>
#define MAXN 1000
int Arr[MAXN + 10]; int G_NUM; // 定义成全局变量方便创建完全二叉树
int G_COUNT = 0; // 记录已经创建的树的节点的个数
int G_NUMBER = 0; // 节点标号,左-中-右依次递增
void BbSort(int Arr[], int n); typedef struct TNode { int data; struct TNode * left; struct TNode * right; }TNODE, *PTNODE; typedef struct QNode { PTNODE data; struct QNode * next; }QNODE, *PQNODE; // 树操作
PTNODE CreateCBT(); void LevelOrderTraversal(PTNODE pRoot); // 用层次遍历的方式建立完全二叉树
void InOrderTraversal(PTNODE pRoot); // 用中序遍历的方式给节点编号
void PreOrderTraversal(PTNODE pRoot); // 用先序遍历的方式给节点赋值
void LevelOrderTraversal2(PTNODE pRoot); // 输出层次遍历结果
typedef struct Queue { PQNODE front; PQNODE rear; }QUEUE, *PQUEUE; // 队列操作
PQUEUE CreatQueue(); void EnQueue(PQUEUE pQueue, PTNODE pTNode); PTNODE DeQueue(PQUEUE pQueue); int IsEmpty(PQUEUE pQueue); int main(void) { int i; PTNODE pRoot; scanf("%d", &G_NUM); for(i = 0; i < G_NUM; i++) scanf("%d", &Arr[i]); BbSort(Arr, G_NUM); pRoot = CreateCBT(); LevelOrderTraversal(pRoot); // 层次遍历的方式建立完全二叉树
InOrderTraversal(pRoot); // 中序遍历标号 // 下面两行代码其实可以用一个层次遍历来代替, 就是给节点赋值的同时输出该值,当然按照AC的角度理解的话,可以不用赋值直接输出
PreOrderTraversal(pRoot); // 先序遍历给节点赋值
LevelOrderTraversal2(pRoot); // 层次遍历的同时输出节点的值
return 0; } void BbSort(int Arr[], int n) { int temp, outer, inner, flag; flag = 1; for(outer = n-1; outer > 0 && flag; outer--) { flag = 0; for(inner = 0; inner < outer; inner++) { if(Arr[inner] > Arr[inner+1]) { temp = Arr[inner]; Arr[inner] = Arr[inner+1]; Arr[inner+1] = temp; flag = 1; } } } } PTNODE CreateCBT() { if(G_COUNT == G_NUM) return NULL; PTNODE root = (PTNODE)malloc(sizeof(TNODE)); root->left = root->right = NULL; G_COUNT++; return root; } void LevelOrderTraversal(PTNODE pRoot) { PTNODE pTNode; PQUEUE pQueue = CreatQueue(); EnQueue(pQueue, pRoot); while(!IsEmpty(pQueue)) { pTNode = DeQueue(pQueue); pTNode->left = CreateCBT(); pTNode->right = CreateCBT(); EnQueue(pQueue, pTNode->left); EnQueue(pQueue, pTNode->right); } } void LevelOrderTraversal2(PTNODE pRoot) { int flag = 0; PTNODE pTNode; PQUEUE pQueue = CreatQueue(); EnQueue(pQueue, pRoot); while(!IsEmpty(pQueue)) { pTNode = DeQueue(pQueue); if(flag) putchar(' '); else flag = 1; printf("%d", pTNode->data); EnQueue(pQueue, pTNode->left); EnQueue(pQueue, pTNode->right); } } void InOrderTraversal(PTNODE pRoot) { if(pRoot) { InOrderTraversal(pRoot->left); pRoot->data = G_NUMBER; G_NUMBER++; InOrderTraversal(pRoot->right); } } void PreOrderTraversal(PTNODE pRoot) { if(pRoot) { pRoot->data = Arr[pRoot->data]; PreOrderTraversal(pRoot->left); PreOrderTraversal(pRoot->right); } } PQUEUE CreatQueue() { PQUEUE pQ = (PQUEUE)malloc(sizeof(QUEUE)); pQ->front = pQ->rear = NULL; return pQ; } void EnQueue(PQUEUE pQueue, PTNODE pTNode) { if(pTNode == NULL) return; PQNODE pQNode= (PQNODE)malloc(sizeof(QNODE)); pQNode->data = pTNode; pQNode->next = NULL; if(pQueue->front == NULL) pQueue->front = pQueue->rear = pQNode; else { pQueue->rear->next = pQNode; pQueue->rear = pQNode; } } PTNODE DeQueue(PQUEUE pQueue) { PTNODE pTNode; if(pQueue->front == NULL) return NULL; if(pQueue->rear == pQueue->front) pQueue->rear = NULL; PQNODE pQNode = pQueue->front; pQueue->front = pQueue->front->next; pTNode = pQNode->data; free(pQNode); return pTNode; } int IsEmpty(PQUEUE pQueue) { if(pQueue->front == NULL) return 1; else
return 0; }
05-树6. Path in a Heap (25)
Insert a sequence of given numbers into an initially empty min-heap H. Then for any given index i, you are supposed to print the path from H[i] to the root.
Input Specification:
Each input file contains one test case. For each case, the first line gives two positive integers N and M (<=1000) which are the size of the input sequence, and the number of indices to be checked, respectively. Given in the next line are the N integers in [-10000, 10000] which are supposed to be inserted into an initially empty min-heap. Finally in the last line, M indices are given.
Output Specification:
For each index i in the input, print in one line the numbers visited along the path from H[i] to the root of the heap. The numbers are separated by a space, and there must be no extra space at the end of the line.
Sample Input:
5 3
46 23 26 24 10
5 4 3
Sample Output:
24 23 10
46 23 10
26 10
/* 考察堆的基本操作 */ #include<stdio.h> // 堆常见的操作有Creat、Insert、Delete、IsFull、IsEmpty这里只关心AC,因此省略了不相干操作的实现
#include<malloc.h>
#define CAPACITY 1000 // 堆的最大容量
#define MIN -10001 // 堆数组中下标为0的元素-哨兵的应赋予的初值 typedef struct Heap { int * arr; int size; // 当前元素的个数
int capacity; // 最大容量
}HEAP, *PHEAP; PHEAP CreateHeap(int capacity); void Insert(PHEAP pHeap, int data); void PrintPath(PHEAP pHeap, int i); // 从下标为i的位置开始打印其父节点的值,直到到达数根为止
int main(void) { int n, m, data, i; PHEAP pHeap; scanf("%d%d", &n, &m); pHeap = CreateHeap(CAPACITY); while(n--) { scanf("%d", &data); Insert(pHeap, data); } while(m--) { scanf("%d", &i); PrintPath(pHeap, i); printf("\n"); } return 0; } PHEAP CreateHeap(int capacity) { PHEAP pHeap = (PHEAP)malloc(sizeof(HEAP)); pHeap->arr = (int *)malloc(sizeof(int) * (capacity+1)); pHeap->arr[0] = MIN; // arr[0]做哨兵,方便查找操作
pHeap->size = 0; pHeap->capacity =capacity; return pHeap; } void Insert(PHEAP pHeap, int data) { int position = ++pHeap->size; // 应该先判堆是否满的,因为测试数据不会导致堆满,因此判断堆是否满的操作省略了
for(; data < pHeap->arr[position/2]; position /= 2) pHeap->arr[position] = pHeap->arr[position/2]; // 向下(数根)过滤节点
pHeap->arr[position] = data; } void PrintPath(PHEAP pHeap, int i) // 从下标为i的位置开始打印其父节点的值,直到到达数根为止
{ int isFirst = 1; while(i) { if(isFirst) isFirst = 0; else printf(" "); printf("%d", pHeap->arr[i]); i /= 2; } }
05-树7. File Transfer (25)
We have a network of computers and a list of bi-directional connections. Each of these connections allows a file transfer from one computer to another. Is it possible to send a file from any computer on the network to any other?
Input Specification:
Each input file contains one test case. For each test case, the first line contains N (2<=N<=104), the total number of computers in a network. Each computer in the network is then represented by a positive integer between 1 and N. Then in the following lines, the input is given in the format:
I c1 c2
where I stands for inputting a connection between c1 and c2; or
C c1 c2
where C stands for checking if it is possible to transfer files between c1 and c2; or
S
where S stands for stopping this case.
Output Specification:
For each C case, print in one line the word "yes" or "no" if it is possible or impossible to transfer files between c1 and c2, respectively. At the end of each case, print in one line "The network is connected." if there is a path between any pair of computers; or "There are k components." where k is the number of connected components in this network.
Sample Input 1:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S
Sample Output 1:
no
no
yes
There are 2 components.
Sample Input 2:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
I 1 3
C 1 5
S
Sample Output 2:
no
no
yes
yes
The network is connected.
/* 写的这个代码有点自注释的感觉了,因此不写思路,它们都藏在我的代码里:~ */ #include<stdio.h> // 经测试,路径压缩和高度差合并两个任取一个实现之就能AC,但是毫无疑问,两者皆实现能够保证最快的速度因而更保险
#include<string.h>
#define MAXN 10000 typedef struct set { int data; int parent; // 采用数组下标的方式指示它的父节点
}SET; SET set[MAXN+10]; // 方便起见,0号单元空着了,每个集合的根节点的parent置为一个负数
int Find(SET set[], int element); // 查找元素属于哪个集合,返回元素所在集合的根,未找到则返回-1
void Union(SET set[], int element1, int element2); // 将两个元素合并到一个集合中,方便起见,元素值放到对应下标中
int SetCount(SET set[], int n); // 统计n个元素构成的集合总数
int main(void) { int n, element1, element2, setCount; char ch; memset(set, 0, sizeof(set)); scanf("%d", &n); while(scanf(" %c", &ch) && ch != 'S') { scanf("%d%d", &element1, &element2); if(ch == 'C') { if(Find(set, element1) != -1 && Find(set, element1) == Find(set, element2)) printf("yes\n"); else printf("no\n"); } else Union(set, element1, element2); } setCount = SetCount(set, n); if(setCount == 1) printf("The network is connected.\n"); else printf("There are %d components.\n", setCount); return 0; } int Find(SET set[], int element) { int root = element; int higher; if(set[element].data != element) // 因为set数组初始为0,而给定的最小输入是2,因此元素不在集合中的话,这个条件成立
return -1; // for(; set[element].parent > 0; element = set[element].parent) // 没有路径压缩,直接超时 // ; // return element;
for(; set[root].parent > 0; root = set[root].parent) ; while(set[element].parent > 0) { higher = set[element].parent; set[element].parent = root; element = higher; } return root; } void Union(SET set[], int element1, int element2) // 高度小的树并到高度大的树上,|parent|代表树的高度
{ int root1, root2; if(Find(set, element1) == -1) // 如果元素不在集合中,则将其单独构成一个只包含其本身的集合
{ set[element1].data = element1; // 注意本行代码和下一行代码的顺序
set[element1].parent = -1; } if(Find(set, element2) == -1) { set[element2].data = element2; set[element2].parent = -1; } root1 = Find(set, element1); root2 = Find(set, element2); if(root1 != root2) { if(set[root1].parent < set[root2].parent) // 如果root1的高度高,就把root2挂到root1上,
{ set[root2].parent = root1; set[root1].parent -= 1; } else { set[root1].parent = root2; set[root2].parent -= 1; } // set[root2].parent = root1; //没有高度控制的代码,在if(root1 != root2)里仅此一行
} return; } int SetCount(SET set[], int n) { int i, count; count = 0; for(i = 1; i <= n; i++) { if(set[i].parent <= 0) // 小于零的元素代表添加到集合中的一个根,等于零的元素代表未添加到集合中的元素,它独自构成一个集合
count++; } return count; }
(XP_JIANG)