二叉搜索树和层序遍历
BTQueue.h
1 #ifndef _BTQUEUE_H_
2 #define _BTQUEUE_H_
3
4 #include <stdio.h>
5 #include <stdlib.h>
6
7 //二叉树节点
8 typedef int Element;
9 typedef struct node NODE;
10 struct node{
11 Element val;
12 NODE* left;
13 NODE* right;
14 };
15
16 //队列节点
17 typedef struct q Qnode;
18 struct q{
19 NODE* data;
20 Qnode *next;
21 };
22
23 //创建队列
24 Qnode* Creat_Queue();
25
26 //判断队列是否为空
27 int Queue_isEmpty(Qnode* a);
28
29 //入队
30 Qnode* In_Queue(Qnode* a,NODE* b);
31
32 //出队
33 NODE* Out_Queue(Qnode* a);
34
35 //计算2的a次方
36 int pow2(int a);
37
38 #endif
二叉搜索树书和层序遍历.c
1 #include "BTQueue.h"
2 #define N 8
3
4 NODE *new_node(int val){
5 NODE *node = (NODE*)malloc(sizeof(NODE));
6 node->val = val;
7 node->left=NULL;
8 node->right=NULL;
9 return node;
10 }
11
12 NODE *insert(NODE *rnode,int val){
13 if(rnode==NULL){
14 return new_node(val);
15 }
16 if(val < rnode->val){
17 rnode->left = insert(rnode->left,val);
18 }else{
19 rnode->right = insert(rnode->right,val);
20 }
21 return rnode;
22 }
23
24 ####二叉树的层序遍历
25 void BT_print(NODE *a)
26 {
27 //如果树为空,输出提示信息“树为空 ”,return结束函数
28 if(!a || !(a->left || a->right)){
29 printf("树为空\n");
30 return;
31 }
32 printf("遍历结果为:\n");
33 //如果树不为空
34 // 创建队列
35 Qnode* q = Creat_Queue();
36 //根节点入队
37 In_Queue(q,a);
38 //当队列不为空,说明队列中还有元素的后继节点没有被访问过
39 int i=1,j=0,count=0;
40 while(!Queue_isEmpty(q)){
41 //出队一个元素,分别访问它的左右儿子
42 NODE *n = Out_Queue(q);
43
44 j++;
45 if(n->val==-2){
46 printf("-- ");
47 count++;
48 }else{
49 printf("%d ",n->val);
50 }
51 if(count==pow2(i-1)){
52 break;
53 }
54 if( j == pow2(i)-1){
55 count = 0;
56 printf("\n");
57 i++;
58 }
59
60 //如果左右儿子仍有后继节点,则将其入队,等待被访问
61
62 if(n->left){
63 In_Queue(q,n->left);
64 }else{
65 NODE *null = (NODE*)malloc(sizeof(NODE));
66 null->val=-2;
67 In_Queue(q,null);
68 }
69 if(n->right){
70 In_Queue(q,n->right);
71 }else{
72 NODE *null = (NODE*)malloc(sizeof(NODE));
73 null->val=-2;
74 In_Queue(q,null);
75 }
76
77 }
78 }
79
80 int main(){
81
82 int nodeValue[N] = {50,40,30,20,10,70,60,20};
83 NODE *root = NULL;
84
85 root = insert(root,nodeValue[0]);
86 for(int i=1;i<N;i++){
87 insert(root,nodeValue[i]);
88 }
89
90 BT_print(root);
91 return 0;
92 }
BTQueue.c
1 #include "BTQueue.h"
2
3 Qnode* Creat_Queue()
4 {
5 Qnode* a = (Qnode*)malloc(sizeof(Qnode));
6 a->next = NULL;
7 return a;
8 }
9 int Queue_isEmpty(Qnode* a)
10 {
11 if(!a || !a->next){
12 return 1;
13 }
14 return 0;
15 }
16
17 Qnode* In_Queue(Qnode* a,NODE* b)
18 {
19 Qnode* p = a;
20 while(p->next){
21 p = p->next;
22 }
23
24 Qnode* n = (Qnode*)malloc(sizeof(Qnode));
25 n->next = NULL; n->data = b;
26 p->next = n;
27 return a;
28 }
29
30 NODE* Out_Queue(Qnode* a)
31 {
32 if(Queue_isEmpty(a)){
33 return NULL;
34 }
35 Qnode* p = a->next;
36 a->next = p->next;
37 NODE* r = p->data;
38 free(p);
39
40 return r;
41 }
42
43 int pow2(int a){
44 int result=1;
45 while(a>0){
46 result *= 2;
47 a--;
48 }
49 return result;
50 }
51
数据:int nodeValue[N] = {50,40,30,20,10,70,60,20};
建立项目目录
用tree命令查看项目结构,提交截图
目录 | 文件 |
---|---|
bin | 可执行文件 |
src | 源代码 |
lib | 目标文件,静态库,动态库 |
include | 头文件 |
test | 调试文件 |
res | 资源文件 |
doc | 文档 |
./ | Makefile |
./ | README |
gcc
gcc -E src/ch1/hello.c -Iinclude -o src/ch1/hello.i
gcc -S src/ch1/hello.c -Iinclude -o src/ch1/hello.s
gcc -c src/ch1/hello.c -I include -o lib/hello.o
hexdump
gcc src/ch1/hello.c -I include -o bin/hello
hello.c
#include <stdio.h>
#include "hello.h"
void say_hello(){
printf("191206say hello\n");
}
int main(){
say_hello();
return 0;
}
hello.h
#ifndef _HELLO_H_
#define _HELLO_H_
/*comments*/
void say_hello();
#endif
更多gcc,参照下面的静态库和动态库
静态库和动态库
静态库制作
ar rcs ../../lib/libmymath.a add.o sub.o div1.o
gcc src/ch1/staticlib.c -o bin/staticlib -L lib -l mymath
warning:隐式声明
函数调用之前,如果没有函数声明和函数定义,那么编译器会帮忙做隐式声明
int add(int ,int ) 变量都自动定义成int类型
这是一件危险的事情,这次是正好碰上了,所以能运行成功
解决方法就是为静态库 配套编写一个头文件
1 #ifndef _STATICLIB_H_
2 #define _STATICLIB_H_
3
4 int add(int,int);
5 int sub(int,int);
6 int div1(int,int);
7
8 #endif
gcc src/ch1/staticlib.c -o bin/staticlib -L lib -l mymath -I include
动态库制作
gcc -c %.c -o %.o -fPIC (生成与位置无关的代码)
gcc -shared -o lib库名.so %.o
gcc -shared -o ../../lib/libmymath.so addd.o subd.o div1d.o
gcc src/ch1/staticlib.c -o bin/dynamiclib -L lib -l mymath -I include
bin/dynamiclib 运行
报错,找不到文件???
原因:动态链接器,会到默认的地方寻找动态库,然而默认的地方,没有libmymath.so
解决:设置环境变量,export LD_LIBRARY_PATH = 库路径
gdb
重新调试,step进入函数看一下
调试到这里,可以判定为空指针异常错误
返回修改代码,再进行调试
上一个问题解决,又爆出了新问题
重新debug 进入函数看一下
好家伙,又是一个空指针异常
r 在free(p)之后,莫名其妙地就变成了NULL
回去给代码调一下顺序,r 在return 之前,莫名其妙地变成了NULL
后来发现代码逻辑出了点问题,r应该返回p的数据,修改源代码
再次调试,还有新的bug。。。
Step进去看一下
又是一个空指针。。。发现代码逻辑不完善,改一下代码
终于正常了
gcc src/ch1/gdb.c -o bin/gdbtest -g
l(list)显示源代码
b(break)设置断点 r(run)运行,遇到断点自然停下
n(nextline)下一行代码 s(step)下一步,会进入函数
p(print)查看变量 display(持续展示变量值)
使用until,运行到指定行,用来跳出循环
使用finish,结束函数
条件断点 b 行号 if 条件
查看、切换栈帧 bt 和 frame (查看不在当前函数栈帧中的变量)
用set args设置命令行的输入的参数
Makefile
src目录下还有多个ch1,ch2...子目录,费了一番功夫
因为不需要整个项目最终生成一个可执行文件a.out,(相反,希望bin目录下面有多个可执行文件,有多个main),所以先注释掉了
1 src = $(wildcard src/*/*.c)
2 obj = $(patsubst %.c,%.o,$(src))
3
4 #obj = $(patsubst %.c,%.o,$(notdir $(src)))
5 #obj0 = $(addprefix lib/,$(notdir $(src)))
6 #obj1 = $(patsubst %.c,%.o,$(obj0))
7 #exe = $(addprefix bin/,$(notdir $(src)))
8 #finalexe = $(patsubst %.c,%,$(exe))
9
10
11 myArgs= -Iinclude -Llib -Wall
12
13 ALL:a.out
14
15 a.out:$(obj)
16 # gcc lib/*.o -o $@ $(myArgs)
17
18 $(obj):%.o:%.c
19 gcc -c $< -o lib/$(notdir $@) $(myArgs)
20 -gcc lib/$(notdir $@) -o bin/$(patsubst %.o,%,$(notdir $@)) $(myArgs)
21 -gcc -g $< -o test/$(patsubst %.o,%,$(notdir $@)) $(myArgs)
22
23 clean:
24 -rm -rf lib/*.o a.out
25
26 .PHONY: clean ALL test
27
28 test:
29 @echo $(src)
30 @echo $(obj)
31 # @echo $(exe)
32 # @echo $(finalexe)