【MOOC课程学习记录】数据结构

看了中国大学MOOC zju的《数据结构》2019夏的第九次开课。做了一些PTA上的习题,没有全做,因为做得慢,老是不会,加上并不能做到一有空就学习,所以做不完了,给跪了Orz。

以后有时间的话,再把剩下的补完吧,估计下次这门网课的内容以及习题变化不多,尤其是后者应该还是这些题目,还有机会再做,那时候就当练练手,防止生疏。这次就先这样吧。

坚持就是胜利!

03-树1 树的同构

#include <stdio.h>

#define MAX 10

typedef struct node{
	char key;
	int left;
	int right;
}tree;

tree a[MAX], b[MAX];

int buildTree(tree *t);
int isIsomorphic(int ra, int rb);

int main(){
	int ra, rb;
	ra = buildTree(a);
	rb = buildTree(b);
	if (isIsomorphic(ra, rb)){
		printf("Yes\n");
	}else{
		printf("No\n");
	}
	return 0;
}

int buildTree(tree *t){
	char tmpLeft, tmpRight;
	int n;
	scanf("%d", &n);
	if (n == 0){
		return -1;
	}
	int check[n];
	for (int i = 0; i < n; i++){
		check[i] = 0;
	}
	for (int i = 0; i < n; i++){
		scanf("\n%c %c %c", &t[i].key, &tmpLeft, &tmpRight);
		if (tmpLeft == '-'){
			t[i].left = -1;
		}else{
			t[i].left = tmpLeft-'0';
			check[t[i].left] = 1;
		}
		if (tmpRight == '-'){
			t[i].right = -1;
		}else{
			t[i].right = tmpRight-'0';
			check[t[i].right] = 1;
		}
	}
	int tmp;
	for (int i = 0; i < n; i++){
		if (check[i] == 0){
			tmp = i;
			break;
		}
	}
	return tmp;
}

int isIsomorphic(int ra, int rb){
	int conclusion;
	/* 一开始犯了低级错误,写了ra == rb == -1。。。
	后来找错误找了半天才意识到不能这样写,而且仔细看编译的结果,编译器是提醒了这件事的。。
	warning果然也都要认真看 */
	if (ra == -1 && rb == -1){
		conclusion = 1;
	}else if (ra == -1 && rb != -1 || ra != -1 && rb == -1){
		conclusion = 0;
	}else{
		if (a[ra].key != b[rb].key){
			conclusion = 0;
		}else{
			if (a[ra].left == -1 && b[rb].left == -1){
				conclusion = isIsomorphic(a[ra].right, b[rb].right);
			/* 下面这个else if里面的条件一开始也犯错了,没有加&&后面的那半,是看了网上的答案
			回过头来看自己的才发现的错误。如果没有那后半句,那么当a[ra]和b[rb]的左右子树都不为空
			时,此时是无法区分“a[ra]的左、右子树和b[rb]的左、右子树分别比较”与
			               “a[ra]的左、右子树和b[rb]的右、左子树分别比较”这两种情况的。而
			这两种情况的应对操作实际上是不同的。 */
			}else if (a[ra].left > -1 && b[rb].left > -1 
				&& a[a[ra].left].key == b[b[rb].left].key){
				conclusion = isIsomorphic(a[ra].left, b[rb].left) 
					&& isIsomorphic(a[ra].right, b[rb].right);
			}else{
				conclusion = isIsomorphic(a[ra].left, b[rb].right) 
					&& isIsomorphic(a[ra].right, b[rb].left);
			}
		}
	}
	return conclusion;
}

03-树2 List Leaves

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
03-树2 List Leaves */
/* 和上一题的输入有些类似,所以数据的读入方面可以直接复制过来,但要有修改。 */
/* 难得的一次编译通过并符合题目要求
(好吧,编译了两次,第一次==错写成=,不过改了之后pintia提交就正确了) */
#include <stdio.h>
#include <stdlib.h>

#define MAX 10
#define Null -1

/* 把树的结点入队后,为了出队时能知道该结点原来的序号用于输出,需要有个index作记录 */
typedef struct tNode{
	int index;
	int left;
	int right;
}tree;

typedef int root;

/* 用数组实现队列时,数组长度记得要比队列里可能存在的最大元素数量多1,
便于判断是否空和是否满两种情况 */
typedef struct q_List{
    struct tNode q[MAX+1];
    int head;
    int tail;
}*queue;

root buildTree(tree *t);
void printLeaves(tree *t, root r);
queue queueCreate(void);
void enqueue(queue p, struct tNode tn);
struct tNode dequeue(queue p);

int main(){
    tree ta[MAX];
	root ra;
	ra = buildTree(ta);
    printLeaves(ta, ra);
	return 0;
}

root buildTree(tree *t){
	char tmpLeft, tmpRight;
	int n;
	scanf("%d", &n);
	int check[n];
	for (int i = 0; i < n; i++){
		check[i] = 0;
	}
	for (int i = 0; i < n; i++){
		scanf("\n%c %c", &tmpLeft, &tmpRight);
		t[i].index = i;
		if (tmpLeft == '-'){
			t[i].left = Null;
		}else{
			t[i].left = tmpLeft-'0';
			check[t[i].left] = 1;
		}
		if (tmpRight == '-'){
			t[i].right = Null;
		}else{
			t[i].right = tmpRight-'0';
			check[t[i].right] = 1;
		}
	}
	int tmp;
	for (int i = 0; i < n; i++){
		if (check[i] == 0){
			tmp = i;
			break;
		}
	}
	return tmp;
}

void printLeaves(tree *t, root r){
    queue tToQ;
	struct tNode tmp;
	int needSpace = 0;
	/* 为了题目要求的,输出的几个序号之间有空格而行末无空格,
	用个参数needSpace */
    tToQ = queueCreate();
    enqueue(tToQ, t[r]);
    while (!(tToQ->head == tToQ->tail)){
		tmp = dequeue(tToQ);
		if (tmp.left == Null && tmp.right == Null){
			/* 符合要求的空格输出靠这个if */
			if (needSpace){
				printf(" ");
			}
			printf("%d", tmp.index);
			needSpace = 1;
		}else{
			if (tmp.left != Null){
				enqueue(tToQ, t[tmp.left]);
			}
			if (tmp.right != Null){
				enqueue(tToQ, t[tmp.right]);
			}
		}
	}
	return;
}

queue queueCreate(void){
	queue tmp = (queue)malloc(sizeof(struct q_List));
	tmp->head = 0;
	tmp->tail = 0;
	return tmp;
}

void enqueue(queue p, struct tNode tn){
	p->q[p->tail] = tn;
	if (p->tail == MAX){
		p->tail = 0;
	}else{
		p->tail += 1;
	}
}

struct tNode dequeue(queue p){
	struct tNode tmp;
	tmp = p->q[p->head];
	if (p->head == MAX){
		p->head = 0;
	}else{
		p->head += 1;
	}
	return tmp;
}

03-树3 Tree Traversals Again

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
03-树3 Tree Traversals Again */

/* 一开始的想法是读到一个push就在树里相应的位置加入一个结点,
但是尝试着写了一部分,感觉到想实现这个效果很麻烦,于是放弃。
又看别人的思路,意识到原来题目中push时数的序列就是先序遍历的结果,而
pop得到的数的序列就是中序遍历的结果,那么这个问题就变成了课程
中讲过的,已知中序遍历和先(或后)序遍历的结果,求后(或先)序遍历的结果。 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct stack{
    int array[30];
    int top;
};

void push(struct stack *s, int key);
int pop(struct stack *s);
void printPostorder(int *postorder, int *preorder, int *inorder, int size);
void getPostorder(int *postorder, int *preorder, int *inorder, int size);

int main(int argc, char const *argv[])
{
    int preorder[30], inorder[30], postorder[30];
    struct stack *s;
    s = (struct stack *)malloc(sizeof(struct stack));
    s->top = -1;
    /* 上面这三行就是创建了一个栈,因为很短,就不写个函数stackCreate之类的了 */
    int n, pre = 0, ino = 0;
    char op[5];
    scanf("%d", &n);
    for (int i = 0; i < n; i++){
        postorder[i] = 8;
    }
    for (int i = 0; i < 2*n; i++){
        scanf("%s", op);
        if (strcmp(op, "Push") == 0){
            scanf("%d", &preorder[pre]);
            push(s, preorder[pre]);
            ++pre;
        }else{
            inorder[ino] = pop(s);
            ++ino;
        }
    }
    printPostorder(postorder, preorder, inorder, n);
    return 0;
}

void push(struct stack *s, int key){
    s->array[++s->top] = key;
    return;
}

int pop(struct stack *s){
    int tmp;
    tmp = s->array[s->top--];
    return tmp;
}

void printPostorder(int *postorder, int *preorder, int *inorder, int size){
    getPostorder(postorder, preorder, inorder, size);
    printf("%d", postorder[0]);
    for (int i = 1; i < size; i++){
        printf(" %d", postorder[i]);
    }
    return;
}

/* 下面这个函数就是解决这个问题的核心部分,基本思路就是,传给这个函数先序遍历和中序遍历的结果、待确定
的后序遍历以及这些数组的元素个数,然后这个函数的效果就是,使得后序遍历的结果明确。
每次调用时,先确定当前给的先序遍历和中序遍历结果对应的二叉树的根结点的值,这个值在后序遍历中自然就是
在最后。然后根据这个值,可以将先序遍历和中序遍历剩下的部分划分为根的左子树的遍历结果和右子树的遍历结果,
然后对这两个子树再调用函数自身。这样递归地解决了问题。 */
void getPostorder(int *postorder, int *preorder, int *inorder, int size){
    if (size == 0){
        return;
    }
    if (size == 1){
        postorder[size-1] = preorder[size-1];
        return;
    }
    int root = preorder[0];
    postorder[size-1] = root;
    int inorderRootIndex, leftSize, rightSize;
    for (int i = 0; i < size; i++){
        if (inorder[i] == root){
            inorderRootIndex = i;
            break;
        }
    }
    leftSize = inorderRootIndex;
    rightSize = size-leftSize-1;
    int *left_preorder, *left_inorder, *left_postorder;
    int *right_preorder, *right_inorder, *right_postorder;
    left_preorder = &preorder[1];
    left_inorder = &inorder[0];
    left_postorder = &postorder[0];
    right_preorder = &preorder[leftSize+1];
    right_inorder = &inorder[leftSize+1];
    right_postorder = &postorder[leftSize];
    getPostorder(left_postorder, left_preorder, left_inorder, leftSize);
    getPostorder(right_postorder, right_preorder, right_inorder, rightSize);
    return;
}

04-树4 是否同一棵二叉搜索树

呃,看了一下讲解,发现自己没有把malloc的东西free掉。不影响这道题提交通过,但是这个做法是不对的,以后注意改。

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
04-树4 是否同一棵二叉搜索树 */

/*
* 这题没什么特别的,就是熟悉一下二叉树的插入操作怎么写。
*/

#include <stdio.h>
#include <stdlib.h>

typedef struct tNode *tree;

struct tNode{
	int key;
	tree left;
	tree right;
};

tree binaryTreeInsert(tree root, int key);
int isSame(tree oriRoot, tree tesRoot);

int main(){
	int N, L;
	while (1){
		scanf("%d", &N);
		if (N == 0){
			break;
		}
		scanf("%d", &L);
		tree ori, tes[L];
		ori = NULL;
		int tmpKey;
		for (int i = 0; i < L; i++){
			tes[i] = NULL;
		}
		for (int i = 0; i < N; i++){
			scanf("%d", &tmpKey);
			ori = binaryTreeInsert(ori, tmpKey);
		}
		for (int i = 0; i < L; i++){
			for (int j = 0; j < N; j++){
				scanf("%d", &tmpKey);
				tes[i] = binaryTreeInsert(tes[i], tmpKey);
			}
		}
		for (int i = 0; i < L; i++){
			if (isSame(ori, tes[i])){
				printf("Yes\n"); 
			}else{
				printf("No\n");
			}
		}
	}
	return 0;
}

tree binaryTreeInsert(tree root, int key){
	if (!root){
		root = malloc(sizeof(struct tNode));
		root->key = key;
		root->left = NULL;
		root->right = NULL;
	}else{
		if (key < root->key){
			root->left = binaryTreeInsert(root->left, key);
		}else if (key > root->key){
			root->right = binaryTreeInsert(root->right, key);
		}
	}
	return root;
}

int isSame(tree oriRoot, tree tesRoot){
	if (oriRoot == NULL && tesRoot == NULL){
		return 1;
	}
	if (oriRoot == NULL && tesRoot != NULL || oriRoot != NULL && tesRoot == NULL){
		return 0;
	}
	int leftSame = 0, rightSame = 0, rootSame = 0;
	if (oriRoot->key == tesRoot->key){
		rootSame = 1;
	}
	leftSame = isSame(oriRoot->left, tesRoot->left);
	rightSame = isSame(oriRoot->right, tesRoot->right);
	if (rootSame && leftSame && rightSame){
		return 1;
	}else{
		return 0;
	}
}

04-树5 Root of AVL Tree

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
04-树5 Root of AVL Tree */

/*
* 这题就是熟悉一下AVL树的基本行为。课程视频里讲AVL树的时候好像没有直接
* 给具体实现的代码,只是讲了个思路,所以做起来着实花了点时间qaq。
*/

#include <stdio.h>
#include <stdlib.h>

typedef struct tNode *balancedBinaryTree;
struct tNode{
    int key;
    int height;
    balancedBinaryTree left;
    balancedBinaryTree right;
};

balancedBinaryTree insert(balancedBinaryTree root, int key);
int getHeight(balancedBinaryTree t);
balancedBinaryTree LLRotation(balancedBinaryTree root);
balancedBinaryTree LRRotation(balancedBinaryTree root);
balancedBinaryTree RRRotation(balancedBinaryTree root);
balancedBinaryTree RLRotation(balancedBinaryTree root);
int maxHeight(int a, int b);

int main(){
    int N;
    scanf("%d", &N);
    balancedBinaryTree root = NULL;
    int tmpKey;
    for (int i = 0; i < N; i++){
        scanf("%d", &tmpKey);
        root = insert(root, tmpKey);
    }
    printf("%d", root->key);
    return 0;
}

balancedBinaryTree insert(balancedBinaryTree root, int key){
    if (!root){
        root = (balancedBinaryTree)malloc(sizeof(struct tNode));
        root->key = key;
        root->height = 0;
        root->left = NULL;
        root->right = NULL;
    }else{
        if (key < root->key){
            root->left = insert(root->left, key);
        }else if (key > root->key){
            root->right = insert(root->right, key);
        }
        if (getHeight(root->left)-getHeight(root->right) == 2){
            if (key < root->left->key){
                root = LLRotation(root);
            }else{
                root = LRRotation(root);
            }
        }else if (getHeight(root->right)-getHeight(root->left) == 2){
            if (key < root->right->key){
                root = RLRotation(root);
            }else{
                root = RRRotation(root);
            }
        }else{
            root->height = maxHeight(getHeight(root->left), getHeight(root->right))+1;
        }
    }
    return root;
}

int getHeight(balancedBinaryTree t){
    int tmp;
    if (!t){
        tmp = -1;
    }else{
        tmp = t->height;
    }
    return tmp;
}

int maxHeight(int a, int b){
    int max = a;
    if (max < b){
        max = b;
    }
    return max;
}

balancedBinaryTree LLRotation(balancedBinaryTree root){
    balancedBinaryTree tmp = root;
    root = root->left;
    tmp->left = root->right;
    root->right = tmp;
    tmp->height = maxHeight(getHeight(tmp->left), getHeight(tmp->right))+1;
    root->height = maxHeight(getHeight(root->left), tmp->height)+1;
    return root;
}

balancedBinaryTree LRRotation(balancedBinaryTree root){
    balancedBinaryTree tmp = root, tmp2 = root->left;
    root = root->left->right;
    tmp->left = root->right;
    tmp2->right = root->left;
    root->left = tmp2;
    root->right = tmp;
    tmp->height = maxHeight(getHeight(tmp->left), getHeight(tmp->right))+1;
    tmp2->height = maxHeight(getHeight(tmp2->left), getHeight(tmp2->right))+1;
    root->height = maxHeight(tmp2->height, tmp->height)+1;
    return root;
}

balancedBinaryTree RRRotation(balancedBinaryTree root){
    balancedBinaryTree tmp = root;
    root = root->right;
    tmp->right = root->left;
    root->left = tmp;
    tmp->height = maxHeight(getHeight(tmp->left), getHeight(tmp->right))+1;
    root->height = maxHeight(tmp->height, getHeight(root->right))+1;
    return root;
}

balancedBinaryTree RLRotation(balancedBinaryTree root){
    balancedBinaryTree tmp = root, tmp2 = root->right;
    root = root->right->left;
    tmp->right = root->left;
    tmp2->left = root->right;
    root->left = tmp;
    root->right = tmp2;
    tmp->height = maxHeight(getHeight(tmp->left), getHeight(tmp->right))+1;
    tmp2->height = maxHeight(getHeight(tmp2->left), getHeight(tmp2->right))+1;
    root->height = maxHeight(tmp->height, tmp2->height)+1;
    return root;
}

04-树6 Complete Binary Search Tree

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
04-树6 Complete Binary Search Tree */

/*
* 这道题的树是完全二叉树,而且需要层序遍历,所以用数组存放这个二叉树是比较好的。
*/

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 1000
int a[MAXSIZE], b[MAXSIZE];

void solve(int aLeft, int aRight, int bRoot);
int getLeftLength(int size);

int compare(const void *a, const void *b){
	return *(int*)a-*(int*)b;
}

int main(){
	int N;
	scanf("%d", &N);
	for (int i = 0; i < N; i++){
		scanf("%d", &a[i]);
	} 
	qsort(a, N, sizeof(int), compare);
	solve(0, N-1, 0);
	printf("%d", b[0]);
	for (int i = 1; i < N; i++){
		printf(" %d", b[i]);
	}
}

void solve(int aLeft, int aRight, int bRoot){
	int size = aRight-aLeft+1;
	if (size == 0){
		return;
	}
	int leftLength = getLeftLength(size);
	b[bRoot] = a[aLeft+leftLength];
	int leftBRoot = 2*bRoot+1;
	int rightBRoot = leftBRoot+1;
	solve(aLeft, aLeft+leftLength-1, leftBRoot);
	solve(aLeft+leftLength+1, aRight, rightBRoot);
}

int getLeftLength(int size){
	int tmp = 1, total = 0, L;
	while (total < size){
		total += tmp;
		tmp *= 2;
	}
	tmp /= 2;
	total -= tmp;
	int bottom = size-total;
	if (bottom <= tmp/2){
		L = (total-1)/2+bottom;
	}else{
		L = (total+tmp-1)/2;
	}
	return L;
}

/* 写完运行发现结果不对才意识到直接按照输入的序列一个一个插入
得到的不是题目里说的完全二叉树,全白做了。。。
所以下面这些就当练练二叉搜索树的实现了,
以后千万想清楚再动手。QAQ 
#include <stdio.h>
#include <stdlib.h>

typedef struct tNode *BST;
struct tNode{
	int key;
	BST left;
	BST right;
};

typedef struct queue_Array{
	BST Q[550];
	int head;
	int tail;
}*queue;

BST insert(BST t, int key);
void levelOrder(BST t);
void freeBST(BST t);

void enqueue(queue q, BST t);
BST dequeue(queue q);

int main(){
	int N;
	scanf("%d", &N);
	BST t = NULL;
	int tmpKey;
	for (int i = 0; i < N; i++){
		scanf("%d", &tmpKey);
		t = insert(t, tmpKey);
	}
	levelOrder(t);
	freeBST(t);
	return 0;
}

BST insert(BST t, int key){
	if (!t){
		t = (BST)malloc(sizeof(struct tNode));
		t->key = key;
		t->left = NULL;
		t->right = NULL;
	}else{
		if (key < t->key){
			t->left = insert(t->left, key);
		}else if (key > t->key){
			t->right = insert(t->right, key);
		}
	}
	return t;
}

void levelOrder(BST t){
	queue q = (queue)malloc(sizeof(struct queue_Array));
	q->head = 0;
	q->tail = 0;
	enqueue(q, t);
	BST tmp;
	while (q->head != q->tail){
		tmp = dequeue(q);
		if (tmp == t){
			printf("%d", tmp->key);
		}else{
			printf(" %d", tmp->key);
		}
		enqueue(q, tmp->left);
		enqueue(q, tmp->right);
	}
	free(q);
	return;
}

void freeBST(BST t){
	if (!t){
		return;
	}
	free(t->left);
	free(t->right);
	free(t);
	return;
}

void enqueue(queue q, BST t){
	if (t){
		q->Q[q->tail++] = t;
	}
	return;
}

BST dequeue(queue q){
	return q->Q[q->head++];
}
*/

04-树7 二叉搜索树的操作集

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
04-树7 二叉搜索树的操作集 */

BinTree Insert( BinTree BST, ElementType X ){
	if (!BST){
		BST = (BinTree)malloc(sizeof(struct TNode));
		BST->Data = X;
		BST->Left = NULL;
		BST->Right = NULL;
	}else{
		if (X < BST->Data){
			BST->Left = Insert(BST->Left, X);
		}else if (X > BST->Data){
			BST->Right = Insert(BST->Right, X);
		}
	}
	return BST;
}
BinTree Delete( BinTree BST, ElementType X ){
	if (!BST){
		printf("Not Found\n");
		// 如果提交上去提示格式错误,可能是没加这个\n,我一开始就少了这个\n 
	}else{
		Position tmp;
		if (X < BST->Data){
			BST->Left = Delete(BST->Left, X);
		}else if (X > BST->Data){
			BST->Right = Delete(BST->Right, X);
		}else{
			if (BST->Left == NULL && BST->Right == NULL){
				tmp = BST;
				BST = NULL;
				free(tmp);
			}else if (BST->Left != NULL && BST->Right != NULL){
				tmp = FindMin(BST->Right);
				BST->Data = tmp->Data;
				BST->Right = Delete(BST->Right, tmp->Data);
			}else{
				tmp = BST;
				if (!BST->Left){
					BST = BST->Right;
				}else{
					BST = BST->Left;
				}
				free(tmp);
			}
		}
	}
	return BST; 
}
Position Find( BinTree BST, ElementType X ){
	while (BST){
		if (X < BST->Data){
			BST = BST->Left;
		}else if (X > BST->Data){
			BST = BST->Right;
		}else{
			return BST;
		}
	}
	return NULL;
}
Position FindMin( BinTree BST ){
	Position tmp = NULL;
	while (BST){
		tmp = BST;
		BST = BST->Left;
	}
	return tmp;
}
Position FindMax( BinTree BST ){
	Position tmp = NULL;
	while (BST){
		tmp = BST;
		BST = BST->Right;
	}
	return tmp;
}

05-树7 堆中的路径

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
05-树7 堆中的路径集 */

/* 注意这题中的小顶堆是一个一个插入元素构建出来的,
不要用全部读入后调整的方法,否则得到的小顶堆可能
不一样 */
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 1001

typedef struct _minHeap{
	int *a;
	int size;
	int length;
}* minHeap;

//void buildMinHeap(minHeap h);
//void heapify(minHeap h, int n);
void insert(minHeap h, int n);
void printPath(minHeap h, int n);

int main(){
	int N, M;
	scanf("%d %d", &N, &M);
	minHeap h;
	h = (minHeap)malloc(sizeof(struct _minHeap));
	h->a = (int*)malloc(sizeof(int)*MAXSIZE);
	h->size = 0;
	h->length = MAXSIZE;
	h->a[0] = -10001;
	int tmpKey; 
	for (int i = 0; i < N; i++){
//		scanf("%d", &h->a[++h->size]);
		scanf("%d", &tmpKey);
		insert(h, tmpKey);
	}
//	buildMinHeap(h);
	int tmpN;
	for (int i = 0; i < M; i++){
		scanf("%d", &tmpN);
		printPath(h, tmpN);
	}
	return 0;
}

void insert(minHeap h, int n){
	int i;
	for (i = ++h->size; h->a[i/2] > n; i /= 2){
		h->a[i] = h->a[i/2];
	}
	h->a[i] = n;
	return;
}

void printPath(minHeap h, int n){
	printf("%d", h->a[n]);
	while (n/2 > 0){
		n /= 2;
		printf(" %d", h->a[n]);
	}
	printf("\n");
}

/* 给定一个序列构成一个小顶堆,未必只能形成一种,
所以通过这个序列形成,还是要看清题目,我又没看清。。
题目要求是插入,我一开始写了下面这些,是读入整个
序列之后再按课上讲的那个O(N)的方法调整顺序形成的,
结果就错了。比如 3 6 2 0 4,通过两种方法形成的
小顶堆就不同 */
//void buildMinHeap(minHeap h){
//	for (int i = h->size/2; i > 0; i--){
//		heapify(h, i);
//	}
//	return;
//}
//
//void heapify(minHeap h, int n){
//	if (n > h->size/2){
//		;
//	}else{
//		int min = h->a[n*2], minIndex = n*2;
//		if (n*2+1 <= h->size){
//			if (min > h->a[2*n+1]){
//				min = h->a[2*n+1];
//				minIndex = 2*n+1;
//			}
//		}
//		if (min < h->a[n]){
//			h->a[minIndex] = h->a[n];
//			h->a[n] = min;
//			heapify(h, minIndex);
//		}
//	}
//	return;
//}

05-树8 File Transfer

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
05-树8 File Transfer */

/* 题目是关于课程中说的并查集的两个基本操作,就是查找和合并 */

#include <stdio.h>

int main(){
    int N;
    scanf("%d", &N);
    int a[N], check[N];
    for (int i = 0; i < N; i++){
        a[i] = -1;
    }
    char op;
    int c1, c2;
    int tmp1, tmp2;
    scanf("%c", &op);
    while (op != 'S'){
        switch (op){
            case 'I':
                scanf("%d %d", &c1, &c2);
                tmp1 = c1-1;
                tmp2 = c2-1;
                while (a[tmp1] >= 0){
                    tmp1 = a[tmp1];
                }
                while (a[tmp2] >= 0){
                    tmp2 = a[tmp2];
                }
                if (a[tmp1] < a[tmp2]){
                    a[tmp1] += a[tmp2];
                    a[tmp2] = c1-1;
                }else{
                    a[tmp2] += a[tmp1];
                    a[tmp1] = c2-1;
                }
                scanf("%c", &op);
                break;
            case 'C':
                scanf("%d %d", &c1, &c2);
                tmp1 = c1-1;
                tmp2 = c2-1;
                while (a[tmp1] >= 0){
                    tmp1 = a[tmp1];
                }
                while (a[tmp2] >= 0){
                    tmp2 = a[tmp2];
                }
                if (tmp1 == tmp2){
                    printf("yes\n");
                }else{
                    printf("no\n");
                }
                scanf("%c", &op);
                break;
            default:
                scanf("%c", &op);
        }
    }
    int cnt = 0;
    for (int i = 0; i < N; i++){
        if (a[i] < 0){
            cnt++;
        }
    }
    if (cnt == 1){
        printf("The network is connected.\n");
    }else{
        printf("There are %d components.\n", cnt);
    }
    return 0;
}

05-树9 Huffman Codes

这题暂时放弃,有两个测试点始终过不了,提示运行错误,但我找了两个小时都没找到错误在哪里。

这里有个C实现的,以后可以对照着再找找看错在哪

https://blog.csdn.net/qq_36770418/article/details/78532042

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXSIZE 63

typedef struct _minHeap{
	int *a;
	int size;
	int length;
}* minHeap;

typedef struct _binaryTree *BT;
struct _binaryTree{
	BT left;
	BT right;
};

minHeap minHeapBuild(int *array, int N);
void minHeapify(minHeap h, int n);
int minHeapDelete(minHeap h);
void minHeapInsert(minHeap h, int n);
void heapFree(minHeap h);

BT BTInsert(BT t, char *s);
int BTLeafNumber(BT t);
void treeFree(BT t);

int main(){
	int N, M;
	scanf("%d", &N); 
	char c[N];
	int f[N];
	char *code[N];
	int depth[N];
	minHeap h;
	for (int i = 0; i < N; i++){
		scanf(" %c %d", &c[i], &f[i]);
	}
	h = minHeapBuild(f, N);
	int minWPL = 0;
	int tmp1, tmp2, tmpSum;
	while (h->size > 1){
		tmp1 = minHeapDelete(h);
		tmp2 = minHeapDelete(h);
		tmpSum = tmp1+tmp2;
		minWPL += tmpSum;
		minHeapInsert(h, tmpSum);
	}
	heapFree(h);
	scanf("%d", &M);
	for (int i = 0; i < M; i++){
		char tmpC, tmpCode[MAXSIZE+10];
		for (int j = 0; j < N; j++){
			scanf(" %c %s", &tmpC, tmpCode);
			int k;
			for (k = 0; k < N; k++){
				if (c[k] == tmpC){
					break;
				}
			}
			code[k] = (char*)malloc(sizeof(strlen(tmpCode)+1));
			strcpy(code[k], tmpCode);
			depth[k] = strlen(code[k]);
		}
		int total = 0;
		for (int j = 0; j < N; j++){
			total += f[j]*depth[j];
		}
		if (total != minWPL){
			printf("No\n");
		}else{
			BT t;
			t = (BT)malloc(sizeof(struct _binaryTree));
			t->left = NULL;
			t->right = NULL;
			for (int j = 0; j < N; j++){
				t = BTInsert(t, code[j]);
			}
			if (BTLeafNumber(t) == N){
				printf("Yes\n"); 
			}else{
				printf("No\n");
			}
			treeFree(t);
		}
		for (int j = 0; j < N; j++){
			free(code[j]);
		}
	}
	return 0;
}

minHeap minHeapBuild(int *array, int N){
	minHeap h;
	h = (minHeap)malloc(sizeof(struct _minHeap));
	h->a = (int*)malloc(sizeof(int)*(MAXSIZE+10));
	h->size = 0;
	h->length = MAXSIZE+10;
	h->a[0] = -1;
	for (int i = 1; i < N+1; i++){
		h->a[i] = array[i-1];
		h->size++;
	}
	for (int i = h->size/2; i > 0; i--){
		minHeapify(h, i);
	}
	return h;
}

void minHeapify(minHeap h, int n){
	int minIndex = n, min = h->a[minIndex];
	if (2*n <= h->size && h->a[2*n] < min){
		minIndex = 2*n;
		min = h->a[minIndex];
	}
	if (2*n+1 <= h->size && h->a[2*n+1] < min){
		minIndex = 2*n+1;
		min = h->a[minIndex];
	}
	if (minIndex != n){
		h->a[minIndex] = h->a[n];
		h->a[n] = min;
		minHeapify(h, minIndex);
	}
	return;
}

int minHeapDelete(minHeap h){
//	main里面保证了使用这个函数时堆至少有2个数,所以就不判断是否空了。 
	int min = h->a[1];
	int tmp = h->a[h->size--], parent, child;
	for (parent = 1; parent*2 <= h->size; parent = child){
		child = parent*2;
		if (child+1 <= h->size && h->a[child+1] < h->a[child]){
			child++;
		}
		if (tmp < h->a[child]){
			break;
		}else{
			h->a[parent] = h->a[child];
		}
	}
	h->a[parent] = tmp;
	return min;
}

void minHeapInsert(minHeap h, int n){
	int tmpIndex = ++h->size;
	while (h->a[tmpIndex/2] > n){
		h->a[tmpIndex] = h->a[tmpIndex/2];
		tmpIndex /= 2; 
	}
	h->a[tmpIndex] = n;
	return;
}

BT BTInsert(BT t, char *s){
//	应该不会有两个相同的编码s这种没什么意义的输入作为测试数据,就不判断相同的情况了 
	BT tmp = t;
	char *st = s;
	while (*st){
		if (*st == '0'){
			if (!tmp->left){
				tmp->left = (BT)malloc(sizeof(struct _binaryTree));
				tmp->left->left = NULL;
				tmp->left->right = NULL;
			}
			tmp = tmp->left;
		}
		if (*st == '1'){
			if (!tmp->right){
				tmp->right = (BT)malloc(sizeof(struct _binaryTree));
				tmp->right->left = NULL;
				tmp->right->right = NULL;
			}
			tmp = tmp->right;
		}
		st++;
	}
	return t;
}

int BTLeafNumber(BT t){
	if (!t){
		return 0;
	}
	if (t->left == NULL && t->right == NULL){
		return 1;
	}
	int total, left, right;
	left = BTLeafNumber(t->left);
	right = BTLeafNumber(t->right);
	total = left+right;
	return total;
}

void treeFree(BT t){
	if (!t){
		return;
	}else{
		treeFree(t->left);
		treeFree(t->right);
		free(t);
	}
}

void heapFree(minHeap h){
	free(h->a);
	free(h);
	return;
}

06-图1 列出连通集

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
06-图1 列出连通集 */

//-------------用邻接矩阵实现的图-------------
#include <stdio.h>
#include <stdlib.h>

#define MAXV 10

/* 图的表示 */
typedef struct mGraph *ptrToGraph;
struct mGraph{
    int numberOfVertex;
    int numberOfEdge;
    int *matrix;
};

/* 边的表示 */
typedef struct eNode *ptrToENode;
struct eNode{
    int v1, v2;
    int weight;
};

/* 顶点的表示 */
typedef int Vertex;

/* 实现BFS过程需要的队列 */
typedef struct queue *ptrToQueue;
struct queue{
    int head;
    int tail;
    Vertex *qArray;
};

// 使全局变量 visited数组全部元素设置为0
void initializeVisited(void);
// 创建一个图的变量
ptrToGraph graphCreate(int numberOfVertex);
// 插入一条边
void edgeInsert(ptrToGraph g, const ptrToENode e);
// DFS
void depthFirstSearch(const ptrToGraph g, Vertex V);
// BFS
void breadthFirstSearch(const ptrToGraph g, Vertex V);
// 最后free图malloc得到的空间
void freeGraph(ptrToGraph g);
// 下面四个是队列有关的操作
ptrToQueue queueCreate(void);
void enqueue(ptrToQueue q, Vertex V);
Vertex dequeue(ptrToQueue q);
void freeQueue(ptrToQueue q);

// 用于表示一个顶点是否已经访问过
int visited[MAXV];

int main(){
    int N, E;
    scanf("%d %d", &N, &E);
    ptrToGraph g;
    g = graphCreate(N);
    ptrToENode e = (ptrToENode)malloc(sizeof(struct eNode));
    for (int i = 0; i < E; i++){
        scanf("%d %d", &e->v1, &e->v2);
        e->weight = 1;
        edgeInsert(g, e);
    }
    free(e);
    initializeVisited();
    for (int i = 0; i < N; i++){
        if (!visited[i]){
            printf("{ ");
            depthFirstSearch(g, i);
            printf("}\n");
        }
    }
    initializeVisited();
    for (int i = 0; i < N; i++){
        if (!visited[i]){
            printf("{ ");
            breadthFirstSearch(g, i);
            printf("}\n");
        }
    }
    freeGraph(g);
    return 0;
}

void initializeVisited(void){
    for (int i = 0; i < MAXV; i++){
        visited[i] = 0;
    }
}

ptrToGraph graphCreate(int numberOfVertex){
    ptrToGraph tmp = (ptrToGraph)malloc(sizeof(struct mGraph));
    tmp->numberOfVertex = numberOfVertex;
    tmp->numberOfEdge = 0;
    tmp->matrix = (int *)malloc(sizeof(int)*numberOfVertex*numberOfVertex);
    for (int i = 0; i < numberOfVertex; i++){
        for (int j = 0; j < numberOfVertex; j++){
            *(tmp->matrix+i*numberOfVertex+j) = 0;
        }
    }
    return tmp;
}

void edgeInsert(ptrToGraph g, const ptrToENode e){
    *(g->matrix + e->v1 * g->numberOfVertex + e->v2) = e->weight;
    ++g->numberOfEdge;
    *(g->matrix + e->v2 * g->numberOfVertex + e->v1) = e->weight;
    ++g->numberOfEdge;
    return;
}

void depthFirstSearch(const ptrToGraph g, Vertex V){
    visited[V] = 1;
    printf("%d ", V);
    for (int i = 0; i < g->numberOfVertex; i++){
        if (*(g->matrix + V*g->numberOfVertex + i) && !visited[i]){
            depthFirstSearch(g, i);
        }
    }
    return;
}

void breadthFirstSearch(const ptrToGraph g, Vertex V){
    ptrToQueue q = queueCreate();
    visited[V] = 1;
    Vertex tmp;
    enqueue(q, V);
    while (q->head != q->tail){
        tmp = dequeue(q);
        printf("%d ", tmp);
        for (int i = 0; i < g->numberOfVertex; i++){
            if (*(g->matrix + tmp*g->numberOfVertex + i) && !visited[i]){
                visited[i] = 1;
                enqueue(q, i);
            }
        }
    }
    return;
}

void freeGraph(ptrToGraph g){
    free(g->matrix);
    free(g);
    return;
}

ptrToQueue queueCreate(void){
    ptrToQueue tmp = (ptrToQueue)malloc(sizeof(struct queue));
    tmp->head = 0;
    tmp->tail = 0;
    tmp->qArray = (Vertex*)malloc(sizeof(Vertex)*MAXV);
    return tmp;
}

void enqueue(ptrToQueue q, Vertex V){
    q->qArray[q->tail++] = V;
    return;
}

Vertex dequeue(ptrToQueue q){
    Vertex tmp = q->qArray[q->head++];
    return tmp;
}

void freeQueue(ptrToQueue q){
    free(q->qArray);
    free(q);
    return;
}


//-------------下面这些是用邻接表实现的图-------------
// 但是用邻接表实现的,输出结果好像不对。这道题花了不少时间了,就不继续想怎么
// 把这种做法修改正确了。反正用邻接矩阵实现的能过。
// 输出结果的问题可能与邻接表插入边时没实现一个顶点的链表的结点的 顶点编号v从小到大排
// #include <stdio.h>
// #include <stdlib.h>

// #define MAXV 10

// typedef int Vertex;

// typedef struct adjListNode * ptrToAdjListNode;
// struct adjListNode{
//     Vertex v;
//     int weight;
//     ptrToAdjListNode next;
// };

// typedef struct{
//     // dataType data;
//     ptrToAdjListNode next;
// }listHead;

// typedef struct lGraph *ptrToGraph;
// struct lGraph{
//     int numberOfVertex;
//     int numberOfEdge;
//     listHead *p;
// };

// typedef struct eNode *ptrToENode;
// struct eNode{
//     int v1, v2;
//     int weight;
// };

// typedef struct queue *ptrToQueue;
// struct queue{
//     int head;
//     int tail;
//     Vertex *qArray;
// };

// void initializeVisited(void);
// ptrToGraph graphCreate(int numberOfVertex);
// void edgeInsert(ptrToGraph g, const ptrToENode e);
// void depthFirstSearch(const ptrToGraph g, Vertex V);
// void breadthFirstSearch(const ptrToGraph g, Vertex V);
// void freeGraph(ptrToGraph g);
// ptrToQueue queueCreate(void);
// void enqueue(ptrToQueue q, Vertex V);
// Vertex dequeue(ptrToQueue q);
// void freeQueue(ptrToQueue q);

// int visited[MAXV];

// int main(){
//     int N, E;
//     scanf("%d %d", &N, &E);
//     ptrToGraph g;
//     g = graphCreate(N);
//     ptrToENode e = (ptrToENode)malloc(sizeof(struct eNode));
//     for (int i = 0; i < E; i++){
//         scanf("%d %d", &e->v1, &e->v2);
//         e->weight = 1;
//         edgeInsert(g, e);
//     }
//     free(e);
//     initializeVisited();
//     for (int i = 0; i < N; i++){
//         if (!visited[i]){
//             printf("{ ");
//             depthFirstSearch(g, i);
//             printf("}\n");
//         }
//     }
//     initializeVisited();
//     for (int i = 0; i < N; i++){
//         if (!visited[i]){
//             printf("{ ");
//             breadthFirstSearch(g, i);
//             printf("}\n");
//         }
//     }
//     freeGraph(g);
//     return 0;
// }

// void initializeVisited(void){
//     for (int i = 0; i < MAXV; i++){
//         visited[i] = 0;
//     }
// }

// ptrToGraph graphCreate(int numberOfVertex){
//     ptrToGraph tmp = (ptrToGraph)malloc(sizeof(struct lGraph));
//     tmp->numberOfVertex = numberOfVertex;
//     tmp->numberOfEdge = 0;
//     tmp->p = (listHead *)malloc(sizeof(listHead)*numberOfVertex);
//     for (int i = 0; i < numberOfVertex; i++){
//         tmp->p[i].next = NULL;
//     }
//     return tmp;
// }

// void edgeInsert(ptrToGraph g, const ptrToENode e){
//     ptrToAdjListNode tmp = (ptrToAdjListNode)malloc(sizeof(struct adjListNode));
//     tmp->v = e->v2;
//     tmp->weight = e->weight;
//     tmp->next = g->p[e->v1].next;
//     g->p[e->v1].next = tmp;
//     ++g->numberOfEdge;
//     tmp = (ptrToAdjListNode)malloc(sizeof(struct adjListNode));
//     tmp->v = e->v1;
//     tmp->weight = e->weight;
//     tmp->next = g->p[e->v2].next;
//     g->p[e->v2].next = tmp;
//     ++g->numberOfEdge;
//     return;
// }

// void depthFirstSearch(const ptrToGraph g, Vertex V){
//     visited[V] = 1;
//     printf("%d ", V);
//     ptrToAdjListNode tmp = g->p[V].next;
//     while (tmp){
//         if (!visited[tmp->v]){
//             depthFirstSearch(g, tmp->v);
//         }
//         tmp = tmp->next;
//     }
//     return;
// }

// void breadthFirstSearch(const ptrToGraph g, Vertex V){
//     ptrToQueue q = queueCreate();
//     visited[V] = 1;
//     Vertex tmp;
//     enqueue(q, V);
//     while (q->head != q->tail){
//         tmp = dequeue(q);
//         printf("%d ", tmp);
//         ptrToAdjListNode tmp2 = g->p[tmp].next;
//         while (tmp2){
//             if (!visited[tmp2->v]){
//                 visited[tmp2->v] = 1;
//                 enqueue(q, tmp2->v);
//             }
//             tmp2 = tmp2->next;
//         }
//     }
//     return;
// }

// void freeGraph(ptrToGraph g){
//     ptrToAdjListNode tmp;
//     for (int i = 0; i < g->numberOfVertex; i++){
//         while (g->p[i].next){
//             tmp = g->p[i].next->next;
//             free(g->p[i].next);
//             g->p[i].next = tmp;
//         }
//     }
//     free(g->p);
//     free(g);
//     return;
// }

// ptrToQueue queueCreate(void){
//     ptrToQueue tmp = (ptrToQueue)malloc(sizeof(struct queue));
//     tmp->head = 0;
//     tmp->tail = 0;
//     tmp->qArray = (Vertex*)malloc(sizeof(Vertex)*MAXV);
//     return tmp;
// }

// void enqueue(ptrToQueue q, Vertex V){
//     q->qArray[q->tail++] = V;
//     return;
// }

// Vertex dequeue(ptrToQueue q){
//     Vertex tmp = q->qArray[q->head++];
//     return tmp;
// }

// void freeQueue(ptrToQueue q){
//     free(q->qArray);
//     free(q);
//     return;
// }

06-图2 Saving James Bond - Easy Version

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
06-图2 Saving James Bond - Easy Version */

/* 我是用图做的,图是用邻接表表示。
实际上,用邻接表来做,挺麻烦的,做完之后看了个别人的
https://www.cnblogs.com/minesweeper/p/5937036.html
这样不套用邻接表或者邻接矩阵的做法,明显简洁很多,可惜我想不到qaq。
然后的话,一开始提交,测试点“最小跳,人工乱序”这个过不了,
实在不知道问题在哪,就百度了一下,
https://blog.csdn.net/qq_39339575/article/details/90046293
这个碰到了和我一样的问题,然后发现确实,我也是漏了几个等于号,
实在是万分感谢这些人的分享。 */

#include <stdio.h>
#include <stdlib.h>

#define YES 1
#define NO 0
// 孤岛的直径
#define DIAMETER 15
#define MAX_CROCODILE 100

typedef struct{
    int x;
    int y;
}vertex;

typedef struct adjListNode *ptrToAdjListNode;
struct adjListNode{
    int vertexIndex;
    int weight;
    ptrToAdjListNode next;
};

typedef struct listHead *ptrToListHead;
struct listHead{
    // dataType data;
    ptrToAdjListNode next;
};

typedef struct lGraph *ptrToGraph;
struct lGraph{
    int numberOfVertex;
    int numberOfEdge;
    ptrToListHead p;
};

typedef struct eNode *ptrToENode;
struct eNode{
    int v1, v2;
    int weight;
};

int squareOfDistance(int x, int y);
ptrToGraph graphCreate(int numberOfVertex);
void edgeInsert(ptrToGraph g, ptrToENode e);
int depthFirstSearch(ptrToGraph g, int vertexIndex);
// 这个graphFree函数本来是想着把malloc的都free掉,结果会导致编译错误,
// 而且这个错误我不懂怎么解决,所以我干脆就注释掉了,做题的话,没有free倒
// 也不会影响通过,不过正确的做法还是要有free的操作。
// void graphFree(ptrToGraph g);

int visited[MAX_CROCODILE];
vertex a[MAX_CROCODILE];
int D;

int main(){
    for (int i = 0; i < MAX_CROCODILE; i++){
        visited[i] = NO;
    }
    int N;
    scanf("%d %d", &N, &D);
    for (int i = 0; i < N; i++){
        scanf("%d %d", &a[i].x, &a[i].y);
    }
    if (1.0*DIAMETER/2+D >= 50){
        printf("Yes\n");
        return 0;
    }
    ptrToGraph g = graphCreate(N);
    ptrToENode e = (ptrToENode)malloc(sizeof(struct eNode));
    for (int i = 0; i < N; i++){
        for (int j = 0; j < N; j++){
            int sqDist = squareOfDistance(a[i].x-a[j].x, a[i].y-a[j].y);
            if (i != j && sqDist <= D*D){
                e->v1 = i;
                e->v2 = j;
                e->weight = sqDist;
                edgeInsert(g, e);
            }
        }
    }
    free(e);
    int answer = NO;
    double sqInit = ((1.0*DIAMETER/2)+D)*((1.0*DIAMETER/2)+D);
    for (int i = 0; i < N; i++){
        int sqDist = squareOfDistance(a[i].x, a[i].y);
        if (sqDist <= sqInit && visited[i] == NO){
            answer = depthFirstSearch(g, i);
        }
        if (answer == YES){
            break;
        }
    }
    if (answer == YES){
        printf("Yes\n");
    }else{
        printf("No\n");
    }
    // graphFree(g);
    return 0;
}

int squareOfDistance(int x, int y){
    return (x*x+y*y);
}

ptrToGraph graphCreate(int numberOfVertex){
    ptrToGraph tmp = (ptrToGraph)malloc(sizeof(struct lGraph));
    tmp->numberOfVertex = numberOfVertex;
    tmp->numberOfEdge = 0;
    tmp->p = (ptrToListHead)malloc(sizeof(struct listHead)*numberOfVertex);
    for (int i = 0; i < numberOfVertex; i++){
        tmp->p[i].next = NULL;
    }
    return tmp;
}

void edgeInsert(ptrToGraph g, ptrToENode e){
    ptrToAdjListNode tmp = (ptrToAdjListNode)malloc(sizeof(struct adjListNode));
    tmp->vertexIndex = e->v2;
    tmp->weight = e->weight;
    tmp->next = g->p[e->v1].next;
    g->p[e->v1].next = tmp;
    ++g->numberOfEdge;
    tmp = (ptrToAdjListNode)malloc(sizeof(struct adjListNode));
    tmp->vertexIndex = e->v1;
    tmp->weight = e->weight;
    tmp->next = g->p[e->v2].next;
    g->p[e->v2].next = tmp;
    ++g->numberOfEdge;
    return;
}

int depthFirstSearch(ptrToGraph g, int vertexIndex){
    int answer = NO;
    visited[vertexIndex] = YES;
    if (a[vertexIndex].x >= 50-D || a[vertexIndex].x <= -50+D || 
        a[vertexIndex].y >= 50-D || a[vertexIndex].y <= -50+D){
        answer = YES;
    }else{
        ptrToAdjListNode tmp = g->p[vertexIndex].next;
        while (tmp){
            if (visited[tmp->vertexIndex] == NO){
                answer = depthFirstSearch(g, tmp->vertexIndex);
            }
            if (answer == YES){
                break;
            }
            tmp = tmp->next;
        }
    }
    return answer;
}

// void freeGraph(ptrToGraph g){
//     ptrToAdjListNode tmp;
//     for (int i = 0; i < g->numberOfVertex; i++){
//         while (g->p[i].next){
//             tmp = g->p[i].next->next;
//             free(g->p[i].next);
//             g->p[i].next = tmp;
//         }
//     }
//     free(g->p);
//     free(g);
//     return;
// }

06-图3 六度空间

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
06-图3 六度空间 */

/* 思路老师在视频里有讲 */

#include <stdio.h>
#include <stdlib.h>

/* 下面三个结构是用来表示图的,这里我用的是邻接表。
第二个是邻接表中链表的头,第一个是链表后面的各个结点,
第三个就是图 */
typedef struct vNode *ptrToVNode;
struct vNode{
    int vertexIndex;
    ptrToVNode next;
};

typedef struct listHead *ptrToListHead;
struct listHead{
    double percent;
    ptrToVNode next;
};

typedef struct lGraph *ptrToGraph;
struct lGraph{
    int numberOfVertex;
    int numberOfEdge;
    ptrToListHead list;
};

/* 这个是表示一条边 */
typedef struct edge *ptrToEdge;
struct edge{
    int v1, v2;
};

/* 队列用于BFS */
typedef struct queue *ptrToQueue;
struct queue{
    int front;
    int rear;
    int *q;
};

/* 使表示结点是否访问过的visited数组的元素全部为0,
0表示没有访问过,1表示访问过 */
void initVisited(int *a, int n);
/* 图的操作 */
ptrToGraph graphCreate(int numberOfVertex);
void graphDestroy(ptrToGraph g);
void edgeInsert(ptrToGraph g, ptrToEdge e);
void listInsert(ptrToListHead h, int vertexIndex);
int breadthFirstSearch(ptrToGraph g, int vertexIndex);
/* 队列的操作 */
ptrToQueue queueCreate(int size);
void enqueue(ptrToQueue q, int vertexIndex);
int dequeue(ptrToQueue q);
void queueDestroy(ptrToQueue q);

int visited[1000];

int main(){
    /* 读入数据 */
    int N, M;
    scanf("%d %d", &N, &M);
    initVisited(visited, N);
    ptrToGraph g = graphCreate(N);
    ptrToEdge e = (ptrToEdge)malloc(sizeof(struct edge));
    for (int i = 0; i < M; i++){
        scanf("%d %d", &e->v1, &e->v2);
        edgeInsert(g, e);
    }
    /* 计算百分比 */
    int cnt;
    for (int i = 0; i < N; i++){
        cnt = breadthFirstSearch(g, i);
        g->list[i].percent = 1.0*cnt/N;
        printf("%d: %.2f%%\n", i+1, g->list[i].percent*100);
        initVisited(visited, N);
    }
    graphDestroy(g);
    return 0;
}

void initVisited(int *a, int n){
    for (int i = 0; i < n; i++){
        a[i] = 0;
    }
    return;
}

ptrToGraph graphCreate(int numberOfVertex){
    ptrToGraph tmp = (ptrToGraph)malloc(sizeof(struct lGraph));
    tmp->numberOfVertex = numberOfVertex;
    tmp->numberOfEdge = 0;
    tmp->list = (ptrToListHead)malloc(sizeof(struct listHead)*numberOfVertex);
    for (int i = 0; i < numberOfVertex; i++){
        tmp->list[i].percent = 0;
        tmp->list[i].next = NULL;
    }
    return tmp;
}

void graphDestroy(ptrToGraph g){
    for (int i = 0; i < g->numberOfVertex; i++){
        ptrToVNode tmp = g->list[i].next;
        while (tmp){
            g->list[i].next = tmp->next;
            free(tmp);
            tmp = g->list[i].next;
        }
    }
    return;
}

/* 因为是无向图,所以邻接表中要进行两次插入操作,我就干脆另用
一个函数,作用是进行一个链表的插入操作。注意我的数组是0到N-1,
题目的输入是1到N,所以这里有需要-1. */
void edgeInsert(ptrToGraph g, ptrToEdge e){
    listInsert(&g->list[e->v1-1], e->v2-1);
    listInsert(&g->list[e->v2-1], e->v1-1);
    g->numberOfEdge += 2;
    return;
}

void listInsert(ptrToListHead h, int vertexIndex){
    ptrToVNode tmp = (ptrToVNode)malloc(sizeof(struct vNode));
    tmp->vertexIndex = vertexIndex;
    tmp->next = h->next;
    h->next = tmp;
    return;
}

/* 这个用老师的思路,我自己想了半天实在是没出来怎么写。 */
int breadthFirstSearch(ptrToGraph g, int vertexIndex){
    ptrToQueue q = queueCreate(g->numberOfVertex);
    visited[vertexIndex] = 1;
    enqueue(q, vertexIndex);
    int tmpVI, level = 0, lastV = vertexIndex, tailV, cnt = 0;
    while (q->front != q->rear){
        tmpVI = dequeue(q);
        if (level <= 6){
            cnt++;
        }
        ptrToVNode tmp = g->list[tmpVI].next;
        while (tmp){
            if (visited[tmp->vertexIndex] != 1){
                visited[tmp->vertexIndex] = 1;
                enqueue(q, tmp->vertexIndex);
                tailV = tmp->vertexIndex;
            }
            tmp = tmp->next;
        }
        if (tmpVI == lastV){
            lastV = tailV;
            level++;
        }
    }
    queueDestroy(q);
    return cnt;
}

ptrToQueue queueCreate(int size){
    ptrToQueue tmp = (ptrToQueue)malloc(sizeof(struct queue));
    tmp->front = 0;
    tmp->rear = 0;
    tmp->q = (int *)malloc(sizeof(int)*size+1);
    return tmp;
}

void enqueue(ptrToQueue q, int vertexIndex){
    q->q[q->rear++] = vertexIndex;
    return;
}

int dequeue(ptrToQueue q){
    return q->q[q->front++];
}

void queueDestroy(ptrToQueue q){
    free(q->q);
    free(q);
    return;
}

09-排序2 Insert or Merge

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
09-排序2 Insert or Merge */

/* 有的时候,测试点不过提示的是答案错误,但实际上可能是程序中有
重复定义、数组越界这些问题导致的。有的时候PTA还真不会对这些情况
提示段错误或者数组越界之类的。就因为这个,我找错误找了几个小时,
一直以为是大的方面,比如思路有问题之类的。 */

/* 这题我的思路是就真的用两个数组存两个原始的序列,然后先试试插入
排序,一次插入后判断一次,不是插入排序再用归并排序。
老师讲了更简单的思路,利用这两种排序区别明显的特点,先判断是不是插入排序的结果,如果是,求得接下来要排序的元素位置;如果不是,再去求归并排序接下来的length。 */

#include <stdio.h>
#include <stdlib.h>

#define MERGESORT 1
#define INSERTIONSORT 2
#define YES 1
#define NO 0

// 判断两个序列是否一样
int isSame(int *a, int *b, int size);
// 一次归并排序
void mergeSort_OneIteration(int *a, int size, int length);
// 将两个序列归并的操作
void merge(int *a, int *tmp, int L, int R, int RightEnd);
// 一次插入排序
void insertionSort_OneIteration(int *a, int size, int position);

int main(){
    int N;
    scanf("%d", &N);
    int a[N], b[N], dest[N];
    int typeOfSort = 0;
    for (int i = 0; i < N; i++){
        scanf("%d", &a[i]);
        b[i] = a[i];
    }
    for (int i = 0; i < N; i++){
        scanf("%d", &dest[i]);
    }
    /* i1表示此次归并排序的length,i2表示此次进行插入排序的元素位置
    另外,注意插入排序实现的时候,这里默认是从第二个元素开始操作,如果
    i2初始为0,测试点“最小N, Ins 第一步没变”这个是过不了的。 */
    /* 下面两个循环用for写起来会简洁点。 */
    int i1 = 1, i2 = 1;
    while (!typeOfSort){
        insertionSort_OneIteration(b, N, i2++);
        if (isSame(b, dest, N)){
            typeOfSort = INSERTIONSORT;
            break;
        }
        if (i2 == N){
            break;
        }
    }
    while (!typeOfSort){
        mergeSort_OneIteration(a, N, i1);
        i1 *= 2;
        if (isSame(a, dest, N)){
            typeOfSort = MERGESORT;
            break;
        }
        /* 这里不需要像上个循环那样判断i1会不会超,因为题目保证了
        使用的排序一定是两者之一,走到这个循环的时候说明不是插入排序,
        那么一定是归并排序,上面那个break一定会发生。 */
    }

    switch (typeOfSort){
        case MERGESORT:
            printf("Merge Sort\n");
            if (i1 < N){
                mergeSort_OneIteration(a, N, i1);
            }
            printf("%d", a[0]);
            for (int i = 1; i < N; i++){
                printf(" %d", a[i]);
            }
            break;
        case INSERTIONSORT:
            printf("Insertion Sort\n");
            if (i2 < N){
                insertionSort_OneIteration(b, N, i2);
            }
            printf("%d", b[0]);
            for (int i = 1; i < N; i++){
                printf(" %d", b[i]);
            }
    }
    return 0;
}

int isSame(int *a, int *b, int size){
    int i;
    for (i = 0; i < size; i++){
        if (a[i] != b[i]){
            break;
        }
    }
    if (i == size){
        return YES;
    }else{
        return NO;
    }
}

void merge(int *a, int *tmp, int L, int R, int RightEnd){
    int L1 = L, R1 = R;
    int i = L;
    while (L1 <= R-1 && R1 <= RightEnd){
        if (a[L1] <= a[R1]){
            tmp[i++] = a[L1++];
        }else{
            tmp[i++] = a[R1++];
        }
    }
    while (L1 <= R-1){
        tmp[i++] = a[L1++];
    }
    while (R1 <= RightEnd){
        tmp[i++] = a[R1++];
    }
    for (int j = L; j <= RightEnd; j++){
        a[j] = tmp[j];
    }
}

void mergeSort_OneIteration(int *a, int size, int length){
    int *tmp = (int*)malloc(sizeof(int)*size);
    int i, j;
    for (i = 0; i <= size-2*length; i += 2*length){
        merge(a, tmp, i, i+length, i+2*length-1);
    }
    if (i < size-length){
        merge(a, tmp, i, i+length, size-1);
    }else{
        for (j = i; j < size; j++){
            tmp[j] = a[j];
        }
    }
    for (int k = 0; k < size; k++){
        a[k] = tmp[k];
    }
    free(tmp);
    return;
}

// 一开始都用的指针来表示元素,比如*(a+i),其实直接点用a[i]就行了
// 我也不知道为什么我会想这么写。。。
void insertionSort_OneIteration(int *a, int size, int position){
    int tmp = *(a+position);
    int i;
    for (i = position-1; i >= 0; i--){
        if (tmp < *(a+i)){
            *(a+i+1) = *(a+i);
        }else{
            break;
        }
    }
    *(a+i+1) = tmp;
    return;
}

09-排序3 Insertion or Heap Sort

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
09-排序3 Insertion or Heap Sort */

/* 和上一题类似。可以一样先判断是不是插入排序,如果是那后续操作和
上一题一样,如果不是,那么需要知道经过堆排序的序列哪一部分待排。因
为至少做了一次排序,所以这个序列一定是前一段可以构成一个最大堆,后
一段是按大小升序排列的,且后一段每个元素都不比最大堆的对顶元素小。
所以只需要从后往前找到第一个比b[0]小的,然后就是基本的堆排序的操作。 */

#include <stdio.h>
#include <stdlib.h>

void insertionSort_OneIteration(int *a, int size, int position);
void heapSort_OneIteration(int *a, int size);
void percolateDown(int *a, int size, int position);

int main(){
    int N;
    scanf("%d", &N);
    int a[N], b[N];
    int i;
    for (i = 0; i < N; i++){
        scanf("%d", &a[i]);
    }
    
    for (i = 0; i < N; i++){
        scanf("%d", &b[i]);
    }
    int position = 0;
    for (i = 0; i < N-1; i++){
        if (b[i] > b[i+1]){
            position = i+1;
            break;
        }
    }
    for (i = position; i < N; i++){
        if (a[i] != b[i]){
            break;
        }
    }
    if (i == N){
        printf("Insertion Sort\n");
        insertionSort_OneIteration(b, N, position);
        printf("%d", b[0]);
        for (int j = 1; j < N; j++){
            printf(" %d", b[j]);
        }
    }else{
        printf("Heap Sort\n");
        // k表示堆的最后一个元素在数组的下标
        int k;
        for (k = N-1; k >= 0; k--){
            if (b[k] < b[0]){
                break;
            }
        }
        heapSort_OneIteration(b, k);
        printf("%d", b[0]);
        for (int j = 1; j < N; j++){
            printf(" %d", b[j]);
        }
    }
    return 0;
}

void insertionSort_OneIteration(int *a, int size, int position){
    int tmp = a[position], i;
    for (i = position-1; i >= 0; i--){
        if (a[i] > tmp){
            a[i+1] = a[i];
        }else{
            break;
        }
    }
    a[i+1] = tmp;
    return;
}

void heapSort_OneIteration(int *a, int size){
    int tmp = a[0];
    a[0] = a[size];
    a[size--] = tmp;
    percolateDown(a, size, 0);
    return;
}

void percolateDown(int *a, int size, int position){
    int tmp = a[position];
    int parent, child;
    for (parent = position; 2*parent+1 <= size; parent = child){
        child = 2*parent+1;
        if (child+1 <= size && a[child] < a[child+1]){
            child = child+1;
        }
        if (a[child] > tmp){
            a[parent] = a[child];
        }
    }
    a[parent] = tmp;
    return;
}

10-排序4 统计工龄

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
10-排序4 统计工龄 */

/* 桶排序 */

#include <stdio.h>

#define MAXIMUM_WORKING_AGE 50
int main(){
    int workingAge[MAXIMUM_WORKING_AGE+1];
    for (int i = 0; i < MAXIMUM_WORKING_AGE+1; i++){
        workingAge[i] = 0;
    }
    int N, tmp;
    scanf("%d", &N);
    for (int i = 0; i < N; i++){
        scanf("%d", &tmp);
        ++workingAge[tmp];
    }
    for (int i = 0; i < MAXIMUM_WORKING_AGE+1; i++){
        if (workingAge[i]){
            printf("%d:%d\n", i, workingAge[i]);
        }
    }
    return 0;
}

10-排序6 Sort with Swap(0, i)

/*  PTA 中国大学MOOC-陈越、何钦铭-数据结构-2019夏 
10-排序6 Sort with Swap(0, i) */

/* 这题有习题讲解的视频。
关键是要想到最小交换次数是怎么求得的。与表排序中环的概念有关 */

/* 如果没有多元环,那么就是全部元素有序,结果是0.
如果有多元环,那么有两种情况:(1)第一个元素为0,那么对每个多元环
都需要先把0换进多元环,再对这个多元环做交换;(2)第一个元素不为0,
那么含0的多元环直接交换,其他的与(1)相同 */

#include <stdio.h>

int main(){
    int N;
    scanf("%d", &N);
    int a[N], table[N], cntS = 0, cntM = 0;
    // flag判断第一个元素是不是0
    int flag = 0;
    for (int i = 0; i < N; i++){
        scanf("%d", &a[i]);
        table[a[i]] = i;
    }
    if (a[0] == 0){
        flag = 1;
    }
    for (int i = 0; i < N; i++){
        if (table[i] == i){
            ++cntS;
        }
    }
    for (int i = 0; i < N; i++){
        if (table[i] != i){
            ++cntM;
            int tmp = a[i], j = i;
            while (table[j] != i){
                a[j] = a[table[j]];
                int tmp2 = table[j];
                table[j] = j;
                j = tmp2;
            }
            a[j] = tmp;
            table[j] = j;
        }
    }
    // 第一个元素是0和不是0的情况不一样
    if (cntM >= 1){
        if (flag){
            printf("%d", N-cntS+cntM);
        }else{
            printf("%d", N-cntS+cntM-2);
        }
    }else{
        printf("0");
    }
    return 0;
}
posted @ 2019-09-05 15:20  Orzst  阅读(311)  评论(0编辑  收藏  举报