void insert(int t)
{
head = iinsert(head, t);
}
node *iinsert(node *p, int t)
{
if (p->val < t) //or if (!p) return p = new node(t, 0); //退出说明不满足if条件,继续后面的执行,而退出可能是因为p->val == t或者p->val > t,因此继续进行判断,从而确定是否要创建新节点
p->next = iinsert(p->next, t);
else if (p->val > t) //a sentinel
{
p = new node(t, p);
n++;
}
return p; //直到return 时,真正的递归才结束,但是递归不变性,可以将递归看作之前的循环已经结束。
}
node *iinsert2(node *p, int t)
{
while (p->val < t) //interrupt because of sentinel or while(p && p->val < t)
p = p->next;
if (p->val > t) //p->val == t, return p
{
p = new node(t, p);
n++;
}
return p;
}
void insert2(int t)
{
node **p;
for (p = &head; (*p)->val < t; p = &((*p)->next))
;
if ((*p)->val == t)
return;
*p = new node(t, p);
n++;
}
以上是链表的插入操作;
void insert(int t)
{
node = iinsert(root, t);
}
node *iinsert(node *p, int t)
{
if (p == 0)
{
p = new node(t);
n++;
}
if (p->val < t)
p->left = iinsert(p->left, t);//递归结束,可能p->val==t, 可能p->val > p, 进而进入判断, 不是尾递归,因此顺序执行后边命令, //事实上前边的判断放置在后边更好,表明顺序执行,这样有助于理解
if (p->val > t)
p->right = iinsert(p->right, t);
if (p->val == t)
return p;
}
以上是二叉树的插入操作。
1 进一步理解哨兵的使用:减少if的判断 , 在数组set, 链表set, 以及箱set的链表实现中,都在insert的操作中添加了哨兵,目的是与之前常规元素的判断一致,而二叉树的哨兵添加,则没有实际意义,因为它的插入判断,没有一致性。
2进一步理解递归,类似与循环不变性,递归有递归不变性,其不变性就是它满足的递归的条件,退出递归,说明不满足递归的不变性
因此,递归可以理解为循环,循环条件就是进入递归的条件,即从if语句开始,所有的语句重复执行,若是尾递归,则“循环”结束后,整个函数调用结束,若不是尾递归,则循环结束后,将会有返回值返回给调用者