1递归(Recursion)

递归就是函数自己调用自己的能力。函数以自己视角来看待问题,问题被一系列的自己所表述

如果一个问题是递归,那么它有一个或多个简单基线(base case)来停止递归自己,其他分线都是一系列的同类小问题。这类问题使用递归函数很容易解决。

比如计算n!

a 首先存在简单基线(停止条件),不需要递归计算。0! = 1;

b 其他分线都能被这样解决:

 -首先解决靠近基线的较小的问题得到较小问题解。

 -然后在小问题解上执行额外的计算得到较大问题的解。

2尾递归(Tail recursion)

如果一个递归函数,除了返回值,其他什么额外操作都不做,那么它就是尾递归的函数。

比如n!

形式这样不是尾递归,因为函数返回还做了n*操作。所以函数调用的stack frame就会保存用来做n*操作
 factorial(n) {

  if (n == 0) return 1;

 return n * factorial(n - 1);

}

而形式: 

factorial1(n, accumulator) {

if (n == 0) return accumulator;

return factorial1(n - 1, n * accumulator);

}

是尾递归,因为函数返回不做其他操作。所以stack frame 不需要保留
尾递归可以等价于如下形式

factorial1(n, accumulator) {

beginning:

if (n == 0) return accumulator;

else {

accumulator *= n;

n -= 1;

 goto beginning;

}

}


或者

  factorial1(n, accumulator) {
    while (n != 0) {
      accumulator *= n;
      n -= 1;
    }
    return accumulator;
  }

=====================================================================

3 树(递归数据结构)

树是由 n 个结点组成的有限集合
如果 n = 0, ,称为空树;如果 n > 0, 则 :
• 有一个特定的称之为根(root)的结点。
• 除根以外的其它结点划分为 m 个互不相交的有限集合,每个集合又是一棵树。


-a 度:结点拥有的子树数称为结点的度

-b层数:从根开始定义起,根为第1层,根的子节点为第2层,以此类推

树中节点的最大层树即为树的高度,或者深度。

-c高度:从该节点起到叶子节点的最长简单路径的边数。(简单路径:无重复边的路径)

-d路径和路径长度: 在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为1,则从根结点到第L层结点的路径长度为L-1

-e结点的权及带权路径长度:  若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。 

-f树的带权路径长度: 树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为WPL

树和链表一样是基于节点node的数据结构。结构里节点指向下一个节点。只是链表只指向一个节点,树可以指向任意多个节点。

因为链表可以很容易的扩展了包含任意数量的元素。所以树的任意节点包含一个链表。链表的每个元素又是一个节点(node).


4 二叉树

二叉树是nn≥0)个结点的有限集合。当n=0时,称为空二叉树;当n>0时,有且仅有一个结点为二叉树的根,其余结点被分成两个互不相交的子集,一个作为左子集,另一个作为右子集,每个子集又是一个二叉树。

满二叉树:二叉树上每一层的节点数目达到最大值。

完全二叉树: 除最外层外,每一层的节点数目达到最大值。且最外层节点集中存在左侧树中。

二叉排序树(BST) : 左子树的值都小于根节点。右子树的值都大于根节点,同时左右子树都是BST。

平衡二叉树(AVL) :任意节点的左右子树的高度差 <= 1。 AVL树检索效率介于 BST 和huffman之间。

最优二叉树(huffman) :树的带权路径长度(WPL)最小的二叉树。

5 二叉树的存储

孩子兄弟链表表示法 
(1)表示方法
     在存储结点信息的同时,附加两个分别指向该结点最左孩子和右邻兄弟的指针域leftmostchild和rightsibling,即可得树的孩子兄弟链表表示。
typedef struct CSNode{
ElemType data;
struct CSNode *firstchild , *netsibling;
} CSNode,* CSTree;
由于二叉树的存储结构比较简单,处理起来也比较方便,所以有时需要把复杂的树,转换为简单的二叉树后再作处理

typedef struct node                   // 结点类型

struct node * lchild ;      // 左孩子指针

     ElemType data ;              // 抽象数据元素类型

     struct node * rchild ;      // 右孩子指针

  }node, *pnode;

 
  注意:
     这种存储结构的最大优点是:它和二叉树的二叉链表表示完全一样。可利用二叉树的算法来实现对树的操作。

6 线索二叉树
二叉树的遍历本质:将一个复杂的非线性结构转换为线性结构,使每个结点都有了唯一前驱和后继(第一个结点无前驱,最后一个结点无后继)
当使用二叉链表存储二叉树时:n个节点有2*n个链指针对吧,实际只用到n-1个,因为除了根以为,每个都有从前驱连入的一条边,这样2*n-(n-1)=n+1个指针空着,浪费可耻啊,需要用啊,于是线索那玩意出现了

利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前趋和后继结点的指针(这种附加的指针称为"线索")。
    这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded   BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
 线索链表中的结点结构为:             
   其中:
     ltag和rtag是增加的两个标志域,用来区分结点的左、右指针域是指向其左、右孩子的指针,还是指向其前趋或后继的线索


       

      
 



































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值