具体的代码及头文件在文章末尾的链接中。
首先说的是头部添加元素和尾部添加元素,头部添加我们先拿到这个数据,然后让这个数据的next区域指针指向头结点,注意:这个头结点是旧的头结点,也就是说这个链表的头结点在数据插入的时候变成了这个链表的第二个数据,但是此时头结点还未指向这个新插入的数据,所以接下来的就是让头结点指向这个新插入的数据,然后让链表的长度加1,此时我们就完成了头部元素的插入。
尾部添加时我们先判断下这个链表的长度是不是等于0,如果链表的长度等于0,那么此时尾部添加的元素也就相当于是在头部添加了,如果链表的长度大于0,那么我们先把链表遍历一遍,拿到最后一个元素,然后把这个要加入的数据放到最后一个数据的后面,之后把链表的长度加1,这样我们就完成了尾添加。
然后再说一下头部删除元素和尾部删除元素。首先是头部删除,我们先判断链表的长度是不是小于等于0,如果小于等于0,直接返回一个假。如果链表的长度大于0,那么我们先定义一个结点指向头结点,然后头指针指向头结点的下一个元素,此时这个头结点的下一个结点就成为了新的头结点,那么我们把旧的头结点即我们刚刚定义的node给释放掉,然后把链表的长度减1,这样我们就把头部的元素给删除了。这里要注意:我们不能直接free(list->head)这个操作,如果直接进行这个操作那么头指针就会与链表断开,同时我们也不能直接进行list->head = list->head->next这个操作,如果这么操作的话我们就没有把第一个元素给删除。
然后是尾部删除,进来也是一样,先判断链表的长度,如果链表的长度小于等于0,那么直接返回假,如果链表的长度等于1,那么我们直接把头指针给free掉就行了,此时不要忘记把头指针置空,还要把链表的长度置0,那么有人可能有问题我们头部删除的时候为什么不判断链表的长度是不是等于1,那是因为就算链表的长度等于1,list->node->next也是等于NULL,然后把头指针指向它(NULL),没有问题。如果链表的长度大于1,那么我们就要先拿到最后一个结点的之前那个结点,即prev,然后我们定义一个tail指针指向链表的最后一个元素,再把最后一个元素之前的那个元素的next置空,这样我们就把最后一个元素断开了,把tail指针给释放掉我们就把最后一个元素给删除了,同时不要忘了把链表的长度减1。
接着说一下从index前插入元素,首先进来我们先判断index这个值合不合法,不合法直接返回false,接着判断index是否等于0,等于0直接调用头添加即可,如果都不是这两种情况,那么,我们就需要拿到这个要插入元素的前面一个元素,即prev,然后把我们要插入元素的next指向prev的next,同时把prev的next指向这个要插入的元素,这样我们就完成了插入操作。这里要注意:我们一定要先把要插入的元素先指向它下一个元素,不能先把之前的那个元素先指向这个要插入的元素,如果先把之前的元素先指向这个要插入的元素,那么这个链表就会断开。程序运行就会出错。
然后我们再说下按值删除元素,进来同样我们先判断链表的长度是否合法,不合法直接返回false,这里先说下cmp,这是个函数指针,以172行为例,当list-head->ptr等于ptr时,我们这个函数就返回0,list->head->ptr 大于 ptr时返回1,反之返回-1,所以这里当ptr等于list->head->ptr时,我们直接调用头删除就行了,如果都不满足这两个条件,那么我们就遍历这个链表,注意我们这里拿到是这个值的要删除的前面那个结点,我们先定义一个临时的结点指向这个要删除的结点,然后让前面那个结点指向后面那个结点,这样我们就把这个值和链表断开了,然后释放临时变量我们就完成了值删除。这里要注意不要忘记返回true,还有不要忘记加prev = prev->next,让结点往下走一个。
源代码地址:(https://gitee.com/Roses_with_thorns/data_structure/blob/master/通用链表)