数据结构对我来说真的好难>< 可能是因为我c语言基础打得不够扎实吧!ε=(´ο`*)))唉,每天告诫自己一定要自己动手写少看(chao)答案、增加思维量。
【明明应该昨天就写完的,但是被拉去入FF14坑了呜呜呜,我就是个废物】
1.题目
假设用顺序表来表示一棵完全二叉树。从根到叶结点按层次从 开始编号,同一层次从左到右编号,数据存储在对应的数组元素中。试编写算法由此顺序存储结构建立该二叉树的二叉链表。
【输入格式】
输入只有一行,为顺序输入的从根节点开始的各个节点元素,它们之间用空格隔开,整个输入以 $ 结束。
【输出格式】
输出有一行,为二叉树结构的广义表达式。
2.完整代码
避免查错的朋友要翻到最后才看到完整代码,先附上完整代码~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef struct BT {
char data;
struct BT *lc, *rc;
} BT;
BT* init(char data) {
BT *node = (BT *)malloc(sizeof(BT));
node->data = data;
node->lc = NULL;
node->rc = NULL;
return node;
}
BT* build(char list[], int len, int id) {
BT *root = init(list[id - 1]);
if (id * 2 <= len) {
root->lc = build(list, len, id * 2);
}
if (id * 2 + 1 <= len) {
root->rc = build(list, len, id * 2 + 1);
}
return root;
}
void clear(BT* bt) {
if (bt->lc != NULL) {
clear(bt->lc);
}
if (bt->rc != NULL) {
clear(bt->rc);
}
free(bt);
}
void gs_print(BT* bt) {
printf("%c", bt->data);
if (bt->lc != NULL) {
printf("(");
gs_print(bt->lc);
if (bt->rc == NULL) {
printf(")");
}
}
if (bt->rc != NULL) {
if (bt->lc == NULL) {
printf("(");
}
printf(",");
gs_print(bt->rc);
printf(")");
}
}
void get_list(char list[]) {
char buf[46] = "";
scanf("%[^$\n]s", buf);
if (strlen(buf) == 0) {
printf("\n");
return ;
}/* else {
printf("Got input:%s", buf);
}*/
char *alphabet;
alphabet = strtok(buf, " ");
char *p = &list[0];
while (alphabet != NULL) {
*p++ = alphabet[0];
alphabet = strtok(NULL, " ");
}
}
int main() {
char s_list[26] = "";
get_list(s_list);
BT *root = build(s_list, (int)strlen(s_list), 1);
gs_print(root);
clear(root);
return 0;
}
3.思路
1-虾米是完全二叉树?
除了0这个编号点完全没有浪费的树(。
非常直观,我们的目的就是让萝卜进坑。
2- 确立要构造的部分
- 初始化的结点
- 提取键入值的部分入list[ ]
- 构造完全二叉树の函数
- 输出伪二叉树表达式の函数
3-Tree根结点初始化及clearの基操
typedef struct BT {
char data;
struct BT *lc, *rc;
} BT;
BT* init(char data) {
BT *node = (BT *)malloc(sizeof(BT));
node->data = data;
node->lc = NULL;
node->rc = NULL;
return node;
}
void clear(BT* bt) {
if (bt->lc != NULL) {
clear(bt->lc);
}
if (bt->rc != NULL) {
clear(bt->rc);
}
free(bt);
}
介个属于常规操作~必须烂熟于心的说( ̄▽ ̄)/ 再错就是大笨蛋!
4-来建立完全二叉树吧!
BT* build(char list[], int len, int id) {
BT *root = init(list[id - 1]); // 数组都是从0开始的,所以要-1!
if (id * 2 <= len) {
root->lc = build(list, len, id * 2);
}
if (id * 2 + 1 <= len) {
root->rc = build(list, len, id * 2 + 1);
}
return root;
}
可以将root也就是我们建立的【二叉树】理解为一个有树形的【数组】!
❀【数组】型的二叉树查找检索起来非常方便和快捷!
5-how get键入的内容呢?
基于数组的顺序存储法:
我们把根节点存储在下标 i = 1 的位置,那左子节点存储在下标 2 * i = 2 的位置,右子节点存储在 2 * i + 1 = 3 的位置。以此类推,B 节点的左子节点存储在 2 * i = 2 * 2 = 4 的位置,右子节点存储在 2 * i + 1 = 2 * 2 + 1 = 5 的位置。
// 此处的list就是存键入鬼东西的数组
void get_list(char list[]) {
char buf[46] = "";
scanf("%[^$\n]s", buf);
if (strlen(buf) == 0) {
printf("\n");
return ;
}/* else {
printf("Got input:%s", buf);
}*/
/**
strtok函数的固定用法!
**/
char *alphabet;
alphabet = strtok(buf, " ");
char *p = &list[0]; //指向list首地址
while (alphabet != NULL) {
*p++ = alphabet[0];
alphabet = strtok(NULL, " ");
}
}
一些语句的注释
① scanf中的[^&xx]
scanf("%[^$\n]s", buf);
/**
scanf本身是不读空格的,加了[^$\n]就表示读入除了换行符以外的内容,
也就是说前面的空字符也会被读取!!
**/
https://blog.csdn.net/hyb612/article/details/111717216
更多用法可以看看这篇博文进行复习~
② strtok干嘛用的捏?
char *strtok(char *str, const char *delim)
- 参数
str – 要被分解成一组小字符串的字符串。
delim –包含分隔符的 C 字符串。(人话:爸爸不读这个分隔符!) - 返回值
该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
在本文里的用法结构:
/** 获取第一个字符串 **/
alphabet = strtok(buf, " ");
char *p = &list[0]; //指向list首地址
/** 获取其余字符串 **/
while (alphabet != NULL) {
*p++ = alphabet[0]; //表示p下一个地址的值 = a的首元素
alphabet = strtok(NULL, " ");
}
- 很难理解这个NULL的用法是什么,
- 看了(https://blog.csdn.net/weibo1230123/article/details/80177898?spm=1001.2014.3001.5506)有一丶悟了!
- 当strtok()在参数s的字符串中发现参数delim中包含的分割字符时,则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回指向被分割出片段的指针。
(ps:‘\0’ 是转义字符 ,为了告诉编译器’\0’是空字符)
6- 打印伪二叉树表达式
主要还是要掌握递归思想,一些技巧:
不要去想接下来的东西是什么样的!
只要想每个未来的对象都=当前对象就可以了!
【结构】
printf最前- 递归的时候要先打印下一个递归项
算法在后- 依据左先右后的先序遍历顺序!
void gs_print(BT* bt) {
printf("%c", bt->data);
if (bt->lc != NULL) {
printf("(");
gs_print(bt->lc);
if (bt->rc == NULL) {
printf(")");
}
}
if (bt->rc != NULL) {
if (bt->lc == NULL) {
printf("(");
}
printf(",");
gs_print(bt->rc);
printf(")");
}
}
推荐一个数据结构可视化网站:
https://visualgo.net/zh
7-main函数没什么好说的
int main() {
char s_list[26] = "";
get_list(s_list);
BT *root = build(s_list, (int)strlen(s_list), 1);
gs_print(root);
clear(root);
return 0;
}
完成でした!!❀❀❀
4.总结
最重要的还是掌握递归调用的思想和字符串分段提取的套路~