概念解析
原因来自我现在自学数据结构与算法,非科班靠着网课自学有点吃力,不过也只能这样了,毕竟考研也不读计算机,只是觉得必须要学好这些知识而已。
回归正题,这是我在学习他人代码时候得到的一些知识想法或者经验,仅作分享,就那种恍然大悟的感觉,你懂吧?
好了,正题正题,我在看了清华大学邓老师的数据结构(不得不说代码是真的吹,看了好久恍然大悟,惊叹如此简单巧妙),有一部分代码不解,思考甚久,终于得到一个过程,或者该说设计逻辑。这部分就在以下的代码分析同步进行。
代码分析
typedef int Rank; //秩
#define ListNodePosi(T) ListNode<T>* //列表节点位置
template <typename T> struct ListNode { //列表节点模板类(以双向链表形式实现)
// 成员
T data; ListNodePosi(T) pred; ListNodePosi(T) succ; //数值、前驱、后继
// 构造函数
ListNode() {} //针对header和trailer的构造
ListNode ( T e, ListNodePosi(T) p = NULL, ListNodePosi(T) s = NULL )
: data ( e ), pred ( p ), succ ( s ) {} //默认构造器
// 操作接口
ListNodePosi(T) insertAsPred ( T const& e ); //紧靠当前节点之前插入新节点
ListNodePosi(T) insertAsSucc ( T const& e ); //紧随当前节点之后插入新节点
以上是链表节点类的构造函数部分(类未完全截取,没必要),关注点在构造函数上,这里使用列表初始化方式,记住这点,再来看下面的
template <typename T> ListNodePosi(T) List<T>::insertA ( ListNodePosi(T) p, T const& e )
{ _size++; return p->insertAsSucc ( e ); } //e当作p的后继插入(After)
以上为在某节点后继部分插入新节点的函数,注意最后的return部分,它所返回的是一个节点,而p是当前操作的节点位置,对p进行函数操作代码如下:
template <typename T> //将e紧随当前节点之后插入于当前节点所属列表(设有哨兵尾节点trailer)
ListNodePosi(T) ListNode<T>::insertAsSucc ( T const& e )
{
ListNodePosi(T) x = new ListNode ( e, this, succ ); //创建新节点
succ->pred = x; succ = x; //设置逆向链接
return x; //返回新节点的位置
}
这只是其中一种操作方式,相当巧妙的地方是,创建新节点,但在初始化的时候,将新节点的前驱初始化为this指针,也就是当前操作的p指针,而后继则是p指针的后继,接下来则是将p的后继的前驱改为指向新节点x,然后p指针的后继再改为指向新节点x,最后返回x节点的位置,这直接用简易的代码做好了插入的操作,令初学者不得不惊叹如此老练的写法