zoukankan      html  css  js  c++  java
  • NetBSD Make源代码阅读三:链表之插入、查找、删除与对每个节点应用函数

    1. 插入节点

    在指定节点后面插入新的节点。这个函数首先检查参数的有效性。然后分两种情况处理插入:

       1> 如果要插入的链表为空,新节点是链表的第一个节点,新初化新节点以后,直接让firstPtr与lastPtr指向这个节点。

       2>如果链表中已有其它节点,就改变前后节点的指针,将新节点插入。

    /*-
     *-----------------------------------------------------------------------
     * Lst_InsertAfter --
     *    创建新节点并插入到所给链表的指定节点之后
     *
     * 输入:
     *    l        操作的链表
     *    ln        在此节点后插入
     *    d        数据
     *
     * :
     *    如果一切正常,返回SUCCESS 
     *
     * 副作用:
     *    创建了新的节点,并链入链表之中。如果ln是链表的最后一个节点链表的变  
     *    量lastPtr将会改变。 
     *    如果链表为空,且ln为NULL,lastPtr 与firstPtr都会改变。 
     *    
     *
     *-----------------------------------------------------------------------
     */
    ReturnStatus
    Lst_InsertAfter(Lst l, LstNode ln, void *d)
    {
        List     list;
        ListNode    lNode;
        ListNode    nLNode;
       
        /*下面两个if语句检查参数的有效性*/
        if (LstValid (l) && (ln == NULL && LstIsEmpty (l))) {
        goto ok;
        }
    
        if (!LstValid (l) || LstIsEmpty (l)  || ! LstNodeValid (ln, l)) {
        return (FAILURE);
        }
        ok: /*参数有效*/
    
        list = l;
        lNode = ln;
    
        /*分配新节点,并链入数据*/
        PAlloc (nLNode, ListNode);           
        nLNode->datum = d;
        nLNode->useCount = nLNode->flags = 0;
    
        if (lNode == NULL) {   /*链表为空*/
        if (list->isCirc) { /*循环链表,节点前后指针指向自身*/
            nLNode->nextPtr = nLNode->prevPtr = nLNode; 
        } else {
            nLNode->nextPtr = nLNode->prevPtr = NULL;/*节点前后指针为NULL*/
        }
        /*既是第一个节点,也是最后一个*/
        list->firstPtr = list->lastPtr = nLNode;  
        } else {
        nLNode->prevPtr = lNode;         
        nLNode->nextPtr = lNode->nextPtr;
    
        lNode->nextPtr = nLNode;
        if (nLNode->nextPtr != NULL) {
            nLNode->nextPtr->prevPtr = nLNode;
        }
    
        if (lNode == list->lastPtr) { /*如果是在最后插入,改变lastPtr*/
            list->lastPtr = nLNode;
        }
        }
    
        return (SUCCESS);
    }

    2. 查找节点

    /*-
     *-----------------------------------------------------------------------
     * Lst_FindFrom --
     *    从指定节点开始查找与所给客户数据一致的节点,使用客户提供的比较函数
     *    来确定数据是否一致。
     *    
     *
     * 结果:
     *    找到的节点或者NULL
     *
     * 副作用:
     *    无
     *
     *-----------------------------------------------------------------------
     */
    LstNode
    Lst_FindFrom(Lst l, LstNode ln, const void *d,
             int (*cProc)(const void *, const void *))
    {
        ListNode    tln;
      
         /*检查参数有效性*/
        if (!LstValid (l) || LstIsEmpty (l) || !LstNodeValid (ln, l)) {
        return NULL;
        }
    
        tln = ln;
    
        /*遍历节点*/
        do {                 
        if ((*cProc)(tln->datum, d) == 0) /*比较节点所含数据与所给的是否一样*/
            return (tln);
        tln = tln->nextPtr;
        } while (tln != ln && tln != NULL);
    
        return NULL;
    }

     

    3. 删除节点

    /*-
     *-----------------------------------------------------------------------
     * Lst_Remove --
     *    删除指定链表的指定节点
     *
     * 返回值:
     *    SUCCESS 或者 FAILURE.
     *
     * 副作用:
     *    如果ln为最后一个节点,firstPtr将被设成NULL. 
     *    如果ln为第一个节点或者最后一个节点,
     *    链表的firsPtr与lastPtreither 将相应地发生变化。
     *-----------------------------------------------------------------------
     */
    ReturnStatus
    Lst_Remove(Lst l, LstNode ln)
    {
        List     list = l;
        ListNode    lNode = ln;
    
        if (!LstValid (l) ||              /*检查参数*/
        !LstNodeValid (ln, l)) {
            return (FAILURE);
        }
    
        /*
         * 从链表中断开链接
         */
        if (lNode->nextPtr != NULL) {
        lNode->nextPtr->prevPtr = lNode->prevPtr;
        }
        if (lNode->prevPtr != NULL) {
        lNode->prevPtr->nextPtr = lNode->nextPtr;
        }
    
        /*
         * 如果 firstPtr或者lastPtr指向这个节点,
         * 则相应地调整它们。
         */
        if (list->firstPtr == lNode) {
        list->firstPtr = lNode->nextPtr;
        }
        if (list->lastPtr == lNode) {
        list->lastPtr = lNode->prevPtr;
        }
    
        /*
         * 顺序访问相关代码.如果我们正在删除的是链表的当前节点 
         * 重新设定当前节点为前一节点. 如果
         * 前一节点不存在(prevPtr == NULL), 把链表的结尾设成
         * Unknown.
         */
        if (list->isOpen && (list->curPtr == lNode)) {
        list->curPtr = list->prevPtr;
        if (list->curPtr == NULL) {
            list->atEnd = Unknown;
        }
        }
    
        /*
         * firstPtr仍然指向ln的唯一一种情况就是它是列表剩下的 
         * 最后一个节点。 (这是循环列表,所以lNode->nextptr == lNode)
         *  因此,删除之后列表为空,要做如下的标记
         */
        if (list->firstPtr == lNode) {
        list->firstPtr = NULL;
        }
    
        /*
         * 注意客户数据(the datum)没有删除。调用者必须
         * 负责释放它。
         */
        if (lNode->useCount == 0) {
        free(ln);
        } else {
        lNode->flags |= LN_DELETED;
        }
    
        return (SUCCESS);
    }

     4. 对节点应用函数

    /*-
     *-----------------------------------------------------------------------
     * Lst_ForEachFrom --
     *    Apply the given function to each element of the given list. The
     *    function should return 0 if traversal should continue and non-
     *    zero if it should abort.
     *
     * Results:
     *    None.
     *
     * Side Effects:
     *    Only those created by the passed-in function.
     *
     *-----------------------------------------------------------------------
     */
    /*VARARGS2*/
    int
    Lst_ForEachFrom(Lst l, LstNode ln, int (*proc)(void *, void *),
            void *d)
    {
        ListNode    tln = ln;
        List     list = l;
        ListNode    next;
        Boolean             done;
        int                 result;
    
        if (!LstValid (list) || LstIsEmpty (list)) {
        return 0;
        }
    
        do {
        /*
         * Take care of having the current element deleted out from under
         * us.
         */
    
        next = tln->nextPtr;
    
        /*
         * We're done with the traversal if
         *  - the next node to examine is the first in the queue or
         *    doesn't exist and
         *  - nothing's been added after the current node (check this
         *    after proc() has been called).
         */
        done = (next == NULL || next == list->firstPtr);
    
        (void) tln->useCount++;
        result = (*proc) (tln->datum, d);
        (void) tln->useCount--;
    
        /*
         * Now check whether a node has been added.
         * Note: this doesn't work if this node was deleted before
         *       the new node was added.
         */
        if (next != tln->nextPtr) {
            next = tln->nextPtr;
            done = 0;
        }
    
        if (tln->flags & LN_DELETED) {
            free((char *)tln);
        }
        tln = next;
        } while (!result && !LstIsEmpty(list) && !done);
    
        return result;
    }
  • 相关阅读:
    phpstudy apache无法启动的解决办法
    Windows server 2008 快速搭建域环境
    使用netsh来进行端口转发
    基于docker构建测试环境
    [Leetcode] Linked List Cycle
    Hyper-V下安装Ossim系统
    Windows应用替代方案接龙
    图解CISCO 3550忘记密码解决方法
    硬件代理解决用户上网问题
    图->存储结构->数组表示法(邻接矩阵)
  • 原文地址:https://www.cnblogs.com/RbtreeLinux/p/3633237.html
Copyright © 2011-2022 走看看