链表API实现(插入,删除,查找)

  使用了NIL来当做链表的头和尾,构建的时候也用插入函数插入,在遍历的时候只要判断当前的指针指向的内容是不是NIL即可。

关于NIL节点的使用:

Node NIL;
Node *nil = &NIL;

关于内存池的使用:

Node pool[MAX];
int poolIndex;
Node* getnew(){
    
    return &pool[poolIndex++];

}

插入的时候对于四个指针进行操作:

    NewNode->pre = dstNode;
    NewNode->next = dstNode->next;

    dstNode->next->pre = NewNode;
    dstNode->next = NewNode;

2017年9月30日10:58:50更新:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

关于插入的时候四个指针操作的顺序可能造成的BUG

  四个指针操作,对于Newnode的操作一般不会有问题,但是对于dst的操作要达到的效果在当前这个例子里面是要实现一个每插入一个元素它的pre指向前一个元素,next指向链表头(即NIL)的数据链式结构。

但是当先把上面的操作中的后两项颠倒一下的时候会出现如下的现象:

  对应代码: dstNode->next = NewNode;

                                    dstNode->next->pre = NewNode;                                     可以看见。我们没插入一个节点并没有指向NIL,而是指向了他自己。原因就在于我们先操作dst->next =newnode的时候更改了dst->next的值,但是我们后面还要用到dst->next的值,所以需要先操作dst->next->pre,然后再操作dst->next.这样才能保证得到如下图的结果:

对应代码:dstNode->next->pre = NewNode;  

                                  dstNode->next = NewNode;

!!!所以得出的结论就是插入的时候为了避免这种BUG,就先对于pre进行操作(包括dst和newnode),然后再对于next进行操作。

---------------------------------------------------2017年9月30日11:11:54---------------------------------------------------------------------------------------------------------------------------------------------

删除的时候对于要删除的节点的前一个节点和后一个节点的两个指针的操作:

    node->pre->next = node->next;
    node->next->pre = node->pre;

完整测试代码:

#include <stdio.h>
#include <malloc.h>
#define MAX 100000
typedef struct node{
    int data;
    struct node *next;
    struct node *pre;
}Node;
Node NIL;
Node *nil = &NIL;
Node pool[MAX];
int poolIndex;
Node* getnew(){
    
    return &pool[poolIndex++];

}
void listInit(){

    nil->next = nil;
    nil->pre = nil;
    nil->data = 0;

}

void listInsertAfter(Node*dstNode,Node*NewNode){

    NewNode->pre = dstNode;
    NewNode->next = dstNode->next;

    dstNode->next->pre = NewNode;
    dstNode->next = NewNode;

}

void listDelete(Node*node){
    
    node->pre->next = node->next;
    node->next->pre = node->pre;

}

Node* search(int key){
    Node *x = nil->next;//从表头的下一个元素开始找
    while (x != nil&&x->data !=key){
        x = x->next;
    }
    return x;//可能返回NIL或者找到的数据的地址
}

void showList(){
    Node * x = nil->next;//从第一个元素开始显示
    while (x != nil){
        printf("%d
", x->data);
        x = x->next;
    }

}
//主函数实现的功能:在链表中添加1到20的数字,然后找到2的位置在它后面添加一个22,然后再利用删除函数删除。
int main(){
    listInit();
    Node *dstnode = getnew();
    dstnode = nil;
    for (int i = 1; i <= 20; i++){
        Node * newnode = getnew();
        newnode->data = i;
        listInsertAfter(dstnode,newnode);
        dstnode = newnode;

    }
    dstnode = search(2);
    Node * newnode = getnew();
    newnode->data = 22;
    listInsertAfter(dstnode, newnode);
    showList();
    dstnode = search(22);
    
    listDelete(dstnode);
    showList();

}
大多数想法要么平庸,要么更糟糕,这很大程度上因为绝妙的想法难得一见,而且他们还要在我们身边这个充斥了各种恶俗的所谓常识的环境中孕育生长。
原文地址:https://www.cnblogs.com/linux0537/p/7597612.html