本章为基本数据结构的一些操作,很基础,当然也很重要。数据结构必须是泛型的,但是C对于泛型的支持只有通过void*强制转换,而且这也不是万能的,比较好的书籍可以参看《C interfaces and implementions》,当然这方面的代码是很成熟的。

ADT在C中的实现大致通过三种方式:静态数组、动态数组和链表。如果不使用指针,那么必须用宏来实现Stack_Type的泛型,push,pop和top的操作数类型都和Stack_Type关联。静态数组的stack实现就是简单的:

#define Stack_Type int
#define Stack_Size 2048
//static array
Stack_Type G_Stack_Node[Stack_Size];
void push(Stack_Type elem);
Stack_Type pop(void);
Stack_Type top(void);

由于引入了全局静态数组,带来了诸如溢出、导出不便的很多问题,所以一般不会采用这种方式。动态数组可以参照std::vector的内存管理方式,如:

 1 #include <malloc.h>
 2 #include <stdlib.h>
 3 #include <assert.h>
 4
 5 #define Stack_Type int
 6 typedef struct stack{
 7     size_t stack_size;
 8     size_t stack_limit;
 9     Stack_Type* stack_name;
10 }Stack;
11
12 Stack* stack_create(void);
13 {
14     Stack* s=malloc(sizeof(*s));
15     assert(s);
16     s->size=0;
17     s->stack_limit=8;
18     s->stack_name=(Stack_Type*)malloc(8*sizeof Stack_Type);
19 }
20 void push(Stack* s,Stack_Type value)
21 {
22     if(s->stack_size==s->stack_limit)
23     {
24         Stack_Type* temp=s->stack_name;
25         s->stack_limit*=2;
26         s->stack_name=(Stack_Type*)malloc(s->stack_limit * sizeof(Stack_Type);
27         memcpy(s->stack_name,temp,s->stack_size * sizeof(Stack_Type);
28         free(temp);
29     }
30     s->stack_name[s->stack_size]=value;
31     s->stack_size+=1;
32 }
33 Stack_Type pop(Stack* s)
34 {
35     if(!s->stack_size)exit(EXIT_FAILTRUE);
36     Stack_Type temp=s->stack_name[--s->stack_size];
37     return temp;
38 }
39 Stack_Type top(Stack* s)
40 {
41     if(!s->stack_size)exit(EXIT_FAILTRUE);
42     return s->stack_name[s->stack_size-1];
43 }
44 void stack_free(Stack* s)
45 {
46     free(s.stack_name);
47     free(s);
48 }

还有就是采用链表的形式实现,需要定义链表结点,下面的实现没有依赖Stack_Type宏,而是使用了泛型指针:

 1 struct node{
 2     void* value;
 3     struct node* link;
 4 };
 5 struct stack{
 6     node* stack_top;
 7     size_t count;
 8 };
 9 typedef struct stack* stack;
10
11 stack stack_create(void)
12 {
13     stack s=(stack)malloc(sizeof(stack));
14     assert(s);
15     s->count=0;
16     s->stack_top=NULL;
17     return s;
18 }
19 void push(stack s,void* v)
20 {
21     struct node* tmp=s->stack_top;
22     s->stack_top=(node*)malloc(sizeof(node));
23     s->stack_top->link=tmp;
24     s->stack_top->value=v;
25     s->count+=1;
26 }
27 void* top(stack s)
28 {
29     if(s->stack_top==NULL)
30         exit(EXIT_FAILTURE);
31     void* r=s->stack_top->value;
32     return r;
33 }
34 void* pop(stack s)
35 {
36     void* r=top(s);
37     s->stack_top=s->stack_top->link;
38     s->count-=1;
39     return r;
40 }
41 void stack_free(stack s)
42 {
43     while(s->stack_top)
44     {
45         node* tmp=s->stack_top;
46         s->stack_top=s->stack_top->link;
47         free(tmp);
48     }
49     free(s);
50 }

队列的实现和接口类似于栈,不同的是队列需要两个指针(或下标),分别指出队列尾部(超出末端的)和头部。如果基于链表来实现队列,不用考虑如何判定边界条件(也可以使用哨兵来简化边界条件),如果基于数组实现,不使用循环数组会造成空间浪费,使用循环数组要注意边界条件不能通过下标的大小关系简单判定。

链表的实现非常简单,在《Pointers on c》这本书里面还讲述了使用指向link字段的指针来简化搜索的技巧(使用指向结点的指针的指针而不是link字段作为循环更迭量)。

树的实现依赖于双链表,可以用两个指针表示任意子女数的树,方法是存放一个指向其最左子节点的指针和一个指向其右边兄弟的指针。

二叉树的遍历:

递归实现很简单,略过…非递归使用堆栈的话,主要有两种思想:

一种是考虑迭代,核心是“访问”。对于前序和中序,节点一旦访问完毕,就可以弹出了,因为我们能保证已弹出节点的所有子树都被访问过。对于后续遍历,弹出节点的同时必须有方法确认节点已经访问过,因为我们无法确定其右子树是否已经访问过(即是入栈访问后弹出还是压根没有入栈过)。所以下面后续遍历的版本1增加了一个变量来确认其右子树已经访问过。(没访问过就入栈右子树,访问过就可以弹出这个节点了)。

第二种是模拟堆栈,核心是“入栈”,即如何布置入栈顺序。比如前序的访问顺序是先根再左后右,那么入栈顺序就是相反的先右后左最后根,其他的类似推理。那么对于栈顶元素何时访问呢?对于前序,是无条件的,对于中序是其左子树已访问过,对于后序则是左右子树均访问过。因此需要一个标记位来确定是否已经访问过,没有访问过就入栈。

  1 #include "stack.h"
  2 bool is_visited(bin_tree* T)
  3 {
  4     if(!T)return true;              //not existed is equal to visited
  5     else return T->isvisited;
  6 }
  7 //使用迭代的思想
  8 void preorder_traversal(bin_tree* T)
  9 {
 10     stack S;
 11     while(T || !is_empty(S))
 12     {
 13         if(T)
 14           {
 15              visit(T);
 16              push(S,T);
 17              T=left(T);
 18           }
 19           else
 20           {
 21              T=pop(S);
 22              T=right(T);
 23           }
 24 }
 25 //直接对递归进行模拟
 26 //即仅考虑入栈和出栈顺序
 27 //状态机
 28 void preorder_traversal_ver2(bin_tree* T)
 29 {
 30     stack S;
 31     if(T)push(S,T)
 32     while(!is_empty(S))
 33     {
 34         bin_tree* tmp=pop(S);
 35         visit(tmp);
 36         if(right(T))push(S,right(T));
 37         if(left(T))push(S,left(T));
 38     }
 39 }
 40 void inorder_traversal(bin_tree* T)
 41 {
 42     stack S;
 43     while(T || !is_empty(S))
 44     {
 45       while(T)
 46       {
 47         push(S,T);
 48         T=left(T);
 49       }
 50       if(!is_empty(S))
 51       {
 52         T=pop(S);
 53         visit(T);
 54         if(right(T))T=right(T);
 55       }
 56     }
 57 }
 58
 59 void inorder_traversal_ver2(bin_tree* T)
 60 {
 61     stack S;
 62     bin_tree* tmp;
 63     if(T)push(S,T)
 64     while(!is_empty(S))
 65     {
 66         tmp=pop(S);             //attention here.
 67         if(!is_visited(left(tmp)))     //left tree is existed and not visited
 68         {
 69             if(right(tmp))push(S,right(tmp));
 70             push(S,tmp);
 71             push(S,left(tmp));
 72         }
 73         else{
 74             visit(tmp);
 75             set_visited(tmp);
 76             if(!left(tmp) && right(tmp))push(S,right(tmp)); //left tree is not existed and right existed
 77         }
 78     }
 79 }
 80 void postorder_traversal(bin_tree* T)
 81 {
 82     stack S;
 83     bin_tree* previsited=NULL;
 84     while(T || !is_empty(S))
 85     {
 86         while(T)
 87         {
 88             push(S,T);
 89             T=left(T);
 90         }
 91         T=top(S);
 92         if(!right(T) || right(T)==previsited)
 93         {
 94             visit(T);
 95             previsited=T;
 96             pop(S);
 97             T=NULL;         //to prevent from pushing left tree twice
 98         }else
 99         T=right(T);
100     }
101 }
102
103 void postorder_traversal_ver2(bin_tree* T)
104 {
105     stack S;
106     bin_tree* tmp;
107     if(T)push(S,T);
108     while(!is_empty(S))
109     {
110       tmp=pop(S);
111       if(is_visited(right(tmp)) && is_visited(left(tmp)))       //left and right both are visited
112       {
113          visit(tmp);
114          set_visited(tmp);
115          pop(S);
116       }else{
117       if(!is_visited(right(tmp)))                               //right first
118         push(S,right(tmp));
119       if(!is_visited(left(tmp)))                                //then left
120         push(S,left(tmp));
121      }
122     }
123 }

当然除了链表外,也可以考虑使用其他技巧实现,比如堆。

本章的习题先略过了…

转载于:https://www.cnblogs.com/livewithnorest/archive/2012/09/03/2665036.html

CLRS2e读书笔记—Chapter10相关推荐

  1. CLRS2e读书笔记—Chapter5 Appendix C

    这部分主要学习概率分析.在概率论的教程里面其实已经学过这些了- 附录C的第一部分是排列组合的基础知识:第二部分是经典概率论:第三部分是离散随机分布的一些概念(期望.方差):第四部分介绍了两个常见的离散 ...

  2. [ZT]640-801中文读书笔记

    [原创]640-801中文读书笔记 作者:红头发 03-22-2004                               打包下载 Noko#sh run ! Written by 红头发 ...

  3. 现代机器人(Modern Robotics):力学,规划,控制读书笔记

    现代机器人:力学,规划,控制读书笔记 在csdn上传主要是可以换积分,文章乱码比较多,有用的话可以来知乎看,目录链接如下,感兴趣可以来看: 现代机器人:力学,规划,控制(chapter1)内容简介 - ...

  4. 【读书笔记】知易行难,多实践

    前言: 其实,我不喜欢看书,只是喜欢找答案,想通过专业的解答来解决我生活的困惑.所以,我听了很多书,也看了很多书,但看完书,没有很多的实践,导致我并不很深入在很多时候. 分享读书笔记: <高效1 ...

  5. 读书笔记:编写高质量代码--web前端开发修炼之道(二:5章)

    读书笔记:编写高质量代码--web前端开发修炼之道 这本书看得断断续续,不连贯,笔记也是有些马虎了,想了解这本书内容的童鞋可以借鉴我的这篇笔记,希望对大家有帮助. 笔记有点长,所以分为一,二两个部分: ...

  6. 《编程匠艺》读书笔记

    <编程匠艺>读书笔记之一 <编程匠艺>读书笔记之二 <编程匠艺>读书笔记之三 <编程匠艺>读书笔记之四 <编程匠艺>读书笔记之五 <编 ...

  7. 《Java: The Complete Reference》等书读书笔记

    春节期间读了下<Java: The Complete Reference>发现这本书写的深入浅出,我想一个问题,书中很多内容我们也知道,但是为什么我们就写不出这样一本书,这么全面,这么系统 ...

  8. oracle直查和call哪个更快,让oracle跑的更快1读书笔记二

    当前位置:我的异常网» 数据库 » <>读书笔记二 <>读书笔记二 www.myexceptions.net  网友分享于:2013-08-23  浏览:9次 <> ...

  9. 《JavaScript面向对象精要》读书笔记

    JavaScript(ES5)的面向对象精要 标签: JavaScript 面向对象 读书笔记 2016年1月16日-17日两天看完了<JavaScript面向对象精要>(参加异步社区的活 ...

  10. 《The Art of Readable Code》 读书笔记 01

    放假前在学校图书馆借了一本新书<The Art of Readable Code>,寒假回来看看,写写其中的Key Idea .summary和一些读书笔记. Preface 前言部分主要 ...

最新文章

  1. 从0到1 html5 canvas,Html5 Canvas学习之路(五)
  2. java开心消消乐代码_今晚请屏住呼吸,开心消消乐拍电影了!
  3. 再读UNPv1:复习、实践、小结
  4. nginx 安装禅道
  5. 修改framework后重新刷入手机
  6. opencv画虚线_(四十四)OpenCV中的机器学习-SVM
  7. visual studio 2019创建项目报错:对com组件的调用返回了错误hresult_fail(未解决)
  8. 无工具arp病毒检测
  9. 嵌入式工程师该如何选择合适的开发系统
  10. 个人中心的html,个人中心.html
  11. Java 集合系列07之 Stack详细介绍(源码解析)和使用示例
  12. LG化学和三星SDI宣布关闭美国电池工厂直至4月13日
  13. 自学硬件真的可行吗?单片机原理知识点之存储器结构的理解(1)
  14. centos7使用kubeadm搭建kubernetes集群
  15. 电子商务网站评价研究与应用分析
  16. 考研408复习思路,学习方法
  17. 小程序实现列表和详情页
  18. activiti7对接springboot
  19. 一文回顾腾讯数字生态大会·微搭低代码专场
  20. 知网查重报告html乱码,知网查重报告出现乱码怎么办

热门文章

  1. [洛谷U22157]刷水题(数位dp)(hash)
  2. ThinkPHP5 模型 - 事务支持
  3. 端口与进程-----Window cmd命令
  4. python3带tkinter窗口的ftp服务器,并使用pyinstaller打包成exe
  5. Android——内存调试
  6. django中时区设置
  7. 用VMWARE学习组网(二)
  8. javafx将数据库内容输出到tableview表格
  9. redhat 阿里镜像
  10. 【maven】maven pom文件详解