200M电信宽带做网站简历模板可编辑
/* 节点结构体定义 */
struct xLIST_ITEM
{TickType_t xItemValue;             /* 辅助值,用于帮助节点做顺序排列 */			struct xLIST_ITEM *  pxNext;       /* 指向链表下一个节点 */		struct xLIST_ITEM *  pxPrevious;   /* 指向链表前一个节点 */	void * pvOwner;					   /* 指向拥有该节点的内核对象,通常是TCB */void *  pvContainer;		       /* 指向该节点所在的链表 */
};
typedef struct xLIST_ITEM ListItem_t;  /* 节点数据类型重定义 */ 
/* 链表结构体定义 */
typedef struct xLIST
{UBaseType_t    uxNumberOfItems;    /* 链表节点计数器 */ListItem_t *   pxIndex;			/* 链表节点索引指针 */MiniListItem_t xListEnd;		/* 链表最后一个节点 */
} List_t; 
/* 将节点插入到链表的尾部 */
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{ListItem_t * const pxIndex = pxList->pxIndex;pxNewListItem->pxNext = pxIndex;                        //1pxNewListItem->pxPrevious = pxIndex->pxPrevious;        //2pxIndex->pxPrevious->pxNext = pxNewListItem;            //3pxIndex->pxPrevious = pxNewListItem;                    //4/* 记住该节点所在的链表 */pxNewListItem->pvContainer = ( void * ) pxList;         //5/* 链表节点计数器++ */( pxList->uxNumberOfItems )++;                          //6
} 
学习过“野火”freeRTOS的童鞋们一定会对这些代码眼熟,我刚学,只是发表一下个人的观点和见解,大神可以直接跳过,写的理解可能只适用于刚接触链表有关知识点的小伙伴,不敢说通俗易懂,但是对于我本身这种菜鸟很容易接受和理解。重点讲解一下第三段代码的逻辑!!!!不喜欢可以敬请喷,我会及时当勉励的。
初始链表结构
假设链表当前结构如下(以便于理解,假设链表已有两个有效节点 A 和 B),并且 pxIndex 是伪头节点,它指向链表的末尾:
NULL <- A <-> B <-> pxIndex -> NULL
 
我们可以将链表节点看成是互相握手的小人,他们按照一定的顺序排列。我们一步步看看新小人 C 是如何加入到一群已经排好队的小人 A、B 和尾巴节点 pxIndex 中的。
初始状态
假设我们有一个双向链表队伍,它的排列如下:
A <-> B <-> pxIndex
 
这里的每个箭头 <-> 表示一个节点和它相邻节点之间的双向关系。pxIndex 可以看作是一个站在队伍最后的标记节点,不是真正的队伍成员。
- A:队伍中的第一个小人,没有人站在他前面。
 - B:A 后面的一个小人。
 - pxIndex:一个标记队伍末尾的小人,没有其他人站在他后面。
 
此时,队伍中的人数为 2(A 和 B),由变量 pxList->uxNumberOfItems 记录。
目标
现在,我们想让小人 C 加入队伍,站在 B 和 pxIndex 之间。最终目标是让队伍变成:
A <-> B <-> C <-> pxIndex
 
插入过程一步步拆解
1. 让 C 知道他后面是谁
 
代码的第一步是让 C 的 pxNext 指针指向 pxIndex,也就是告诉 C 站在他后面的是 pxIndex:
pxNewListItem->pxNext = pxIndex;
 
现在 C 的 pxNext 指针指向了 pxIndex,表示他知道了自己后面是队伍的尾巴节点。
A <-> B     C -> pxIndex
 
2. 让 C 知道他前面是谁
 
接下来,我们需要告诉 C 站在他前面的是 B。我们通过 pxIndex->pxPrevious 找到 B,然后把 B 的地址赋给 C 的 pxPrevious 指针:
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
 
现在 C 的 pxPrevious 指针指向了 B,表示 C 知道了他前面是谁。
A <-> B <-> C -> pxIndex
 
3. 让 B 知道他后面多了一个人
 
在队伍中,双向链表是彼此双向连接的。所以我们还需要告诉 B,让他知道后面站了一个新小人 C。我们通过 pxIndex->pxPrevious->pxNext 找到 B 的 pxNext,然后把 C 的地址赋给它:
pxIndex->pxPrevious->pxNext = pxNewListItem;
 
这样 B 的 pxNext 指针指向了 C,表示 B 知道他后面站了一个新成员 C。
A <-> B <-> C -> pxIndex
 
4. 更新队尾指针,表示 C 是最后一个人
 
队尾指针 pxIndex->pxPrevious 需要指向新插入的节点 C,表示队伍的最后一个有效成员是 C。因此,pxIndex->pxPrevious = pxNewListItem;:
pxIndex->pxPrevious = pxNewListItem;
 
现在 pxIndex->pxPrevious 指向了 C,表示 C 成为新的尾巴前的最后一个节点。
A <-> B <-> C <-> pxIndex
 
5. 记录新节点 C 的所属链表
 
我们把 pxList 的地址存储在 C->pvContainer 中,方便以后找到 C 属于哪个链表:
pxNewListItem->pvContainer = ( void * ) pxList;
 
6. 更新链表节点计数器
最后,链表节点数量增加了 1:
( pxList->uxNumberOfItems )++;
 
现在链表计数器变成了 3,准确记录了链表中有 A、B、C 三个节点。
总结
整个过程简单来说,就是让新节点 C 找到他前后的人,同时告诉他前后的人有了新成员 C,最后更新链表的头尾标记和计数器。
看到这里,你是不是已经完全理解和消化掉了如何插入新节点呢?会不会有一点点疑问,但是又不好意思问呢?我自我提问几个问题吧,因为太菜因为c学的不到位,所以就问题多多了一些。
Question One:
为什么pxIndex->pxPrevious代表的是B?????
答:
在这个链表结构中,pxIndex 是一个伪尾节点(或称标记节点),它作为链表的终点标记。因为 pxIndex 并不是真正的有效数据节点,它的作用只是指示链表的尾部。链表中的实际有效节点依次连接,而 pxIndex 在链表结构上只是方便操作的一个标记。
让我们来看看为什么 pxIndex->pxPrevious 会代表链表的最后一个有效节点 B。
伪尾节点(pxIndex)的工作方式
在这个双向链表中:
pxIndex总是指向链表的尾部,并且它的pxNext通常指向NULL或自己,以表示链表的终止。pxIndex->pxPrevious是链表最后一个有效节点。这是因为链表的逻辑结构让pxIndex成为尾节点标记,那么它的pxPrevious指针自然指向链表中真正的最后一个有效节点。
当前链表的结构示例
假设链表中有两个有效节点 A 和 B,链表的结构如下:
NULL <- A <-> B <-> pxIndex
 
在这个结构中:
A是链表的第一个有效节点,所以A->pxPrevious是NULL。B是链表中最后一个有效节点,所以B->pxNext指向pxIndex。pxIndex是链表的伪尾节点,所以pxIndex->pxPrevious指向B。
插入新节点的操作
当我们向链表末尾插入新节点 C 时,步骤如下:
- 新节点 
C的pxPrevious被设置为当前最后一个有效节点,即pxIndex->pxPrevious,也就是B。 B->pxNext被更新为C,表示B的后面现在是C。pxIndex->pxPrevious更新为C,表示C成为链表中的新最后一个有效节点。
最终,链表结构变为:
NULL <- A <-> B <-> C <-> pxIndex
 
小结
因此,pxIndex->pxPrevious 总是指向链表的最后一个有效节点。这是因为 pxIndex 是一个伪尾节点,它自己没有有效数据,只是标记链表的终点。
Question Two:
pxIndex->pxPrevious->pxNext = pxNewListItem;为什么pxNewListItem是c的地址,pxNewListItem不是包括C的next和previous嘛?
答:
在这段代码中,pxNewListItem 是一个指向新节点的指针,表示整个新节点 C 的地址。这个指针本身包含了新节点的所有信息,包括它的 pxNext 和 pxPrevious 指针。
当我们写 pxIndex->pxPrevious->pxNext = pxNewListItem; 时,我们在做的实际上是更新链表中前一个节点的 pxNext 指针,使它指向新节点 C。这一步的关键在于理解双向链表节点之间的指针如何相互指向,并构成链表结构。
让我们深入理解一下这里的具体含义。
理解 pxNewListItem 的作用
 
-  
pxNewListItem作为新节点的整体指针pxNewListItem指向整个节点C,即包含了C的pxNext和pxPrevious等信息。因此,pxNewListItem并不是指向C的某个特定成员,而是指向节点C本身的起始地址。 -  
在链表中建立前后关系
在链表中,每个节点的pxNext和pxPrevious指针都用于指向相邻节点。这段代码: 
pxIndex->pxPrevious->pxNext = pxNewListItem;
 
-  
等效于
B->pxNext = pxNewListItem,其中B是pxIndex->pxPrevious指向的最后一个有效节点。这一步就是让B->pxNext指向新节点C的整体地址(即pxNewListItem),表示B的下一个节点现在是C。通过这一指向关系的设置,B和C之间的链接建立起来了。 -  
为什么是整个
C的地址pxNewListItem的确包含C的pxNext和pxPrevious指针,但在这行代码中,我们只关心将pxNewListItem作为一个完整的节点地址赋给B->pxNext,表示B后面的节点是C。pxNext和pxPrevious的详细信息只有在访问节点C本身时才会被读取和使用。 
代码工作流程小结
pxNewListItem->pxNext = pxIndex;:将C->pxNext指向pxIndex,表示C后面是伪尾节点pxIndex。pxNewListItem->pxPrevious = pxIndex->pxPrevious;:将C->pxPrevious指向B(原最后一个节点)。pxIndex->pxPrevious->pxNext = pxNewListItem;:将B->pxNext指向C,即B现在知道他后面是C。pxIndex->pxPrevious = pxNewListItem;:将pxIndex->pxPrevious更新为C,即C成为新的最后一个有效节点。
总结
在 pxIndex->pxPrevious->pxNext = pxNewListItem; 中,pxNewListItem 表示整个新节点 C 的地址,而不只是它的 pxNext 或 pxPrevious。我们通过这个赋值操作让 B->pxNext 指向 C 的地址,从而把 C 插入到 B 和 pxIndex 之间。
