线性表之单链表

单链表的形式:

  单链表的每节点中除了数据域外,还包含一个指针域,用来指向下一个节点,主要有带头结点和不带头结点两种

  单链表定义如下:

//单链表结构体定义
typedef struct LNode {
    int data;
    struct LNode* next;
}LNode;

单链表中的两种基本算法:

插入操作:

  .不妨设在节点A和节点B直间插入节点S,则具体分两步实现:

  •   节点S指向节点B,
//让节点S指向B
S->next = A->next;
  •   节点A指向S
//节点A指S
A->next = S

  注意,这两步的顺序不能弄反,否则会丢失数据;

删除操作:

  同理,不妨设删除节点B,则只需要找到前一个节点A即可,具体实现如下:

//p是要删除的节点
p = A->next;
A->next = A->next->next;
//释放节点B的空间
free(p);

具体的相关算法实现:

头插法建立单链表:

  插入的新节点在表头,旧的节点在新节点之后,不妨设已有头节点B,现插入节点A,则形式为A->B,关键代码如下所示:

  

A->next = B->next;
B->next=A;

  具体实现如下:

  

//插入的节点在表头
STATUS CreateListOfF(LNode *&P, int a[], int n) {
    //s用来指向新申请的节点
    LNode* s;
    int i;
    //申请P的头结点
    P =(LNode*) malloc(sizeof(LNode));
    P->next = NULL;

    for (i = 0; i < n; i++) {
        s = (LNode*)malloc(sizeof(LNode));
        s->data = a[i];
        //新节点指向旧节点
        s->next = P->next;
        //新节点称为新的开始节点
        P->next = s;
    }

    return OK;
}

尾插法建立单链表如下所示:

  关键在于新插入的节点在链表的尾部,不妨设最后插入的节点是F,则最后必须加上F->next = NULL,具体实现如下:

  

//插入的节点在表尾
STATUS CreateListOfR(LNode *&P, int a[], int n) {
    //s指向新申请的节点,r直线链表的终端节点
    LNode *s,*r;
    int i;
    //头结点的申请
    P = (LNode*)malloc(sizeof(LNode));
    P->next = NULL;
    r = P;
    for (i = 0; i < n; i++) {
        s = (LNode*)malloc(sizeof(LNode));
        s->data = a[i];
        
        //r指向终端节点
        r->next = s;
        r = s;
    }
    r->next = NULL;
    return OK;

}

打印链表元素:

STATUS PrintList(LNode *P) {
    if (P->next == NULL) {
        return ERROR;
    }

    while (P->next != NULL) {
        cout << P->next->data << "	";
        P = P->next;
    }
    cout << endl;
    return OK;
}

 查找某个元素并将其删除:

  删除元素两个关键点:

  • 待删除节点的查找;
  • 待删除节点的前驱节点;

  具体实现如下:

  

STATUS FindAndDel(LNode *&P,int x) {
    //pre指向待删除节点的前一个节点
    LNode *pre, *p;
    p = P->next;
    pre = P;
    while (p != NULL) {
        if (p->data == x) {
            break;
        }
        pre = p;
        p = p->next;
    }
    
    //查找部分结束
    if (p == NULL) {
        return ERROR;
    }
    else {
        //让p前驱节点指向p后继节点
        pre->next = p->next;
        free(p);
        return OK;
    }


}

将两个有序递增链表A、B合并成一个递增有序链表C:

  递增有序链表在这使用尾插法,将两个有序的链表的元素一一比较,将较小的一个插入C中,依次递推。

  注意: A和B中的元素有可能一个已经完全插入,另外一个部分插入。不妨设A完全插入,B部分插入,这说明B的剩下元素完全大于B,这是只需要将B接入C即可;

  具体实现如下:

STATUS MergeListRise(LNode *A, LNode *B, LNode *&C) {
    LNode *pA = A->next;
    LNode *pB = B->next;
    C = A;
  C->next = NULL;
//r始终指向C节点 LNode *r; r = C; free(B); while (pA != NULL&&pB != NULL) { if (pA->data <= pB->data) { r->next = pA; r = pA;
       pA = pA->next; }
else { r->next = pB; r = pB;
       pB = pB->next; } } r
->next = NULL; //处理有一部分插完而另外一部分未插完; if (pA != NULL) { r->next = pA; } if (pB->next != NULL) { r->next = pB; } return OK; }

将两个有序递增链表A、B合并成一个递减有序链表C:

  同上述合并成一个递增有序链表类似,但这里使用头插法构建C,不需要r指针指向C的尾节点,具体实现如下:

  

STATUS MergeListFall(LNode *A, LNode *B, LNode *&C) {
    LNode *pA = A->next;
    LNode *pB = B->next;

    C = A;
    C->next = NULL;

    free(B);
    //s指向待插入的节点
    LNode *s;

    while (pA!=NULL&&pB!=NULL)
    {
        if (pA->data <= pB->data) {
            //取得待插入节点s
            s = pA;
            pA = pA->next;
            s->next = C->next;
            C->next = s;
        }
        else
        {
            s = pB;
            pB = pB->next;
            s->next = C->next;
            C->next = s;
        }
    }

    //当某一个链表先处理完时
    while (pA != NULL)
    {
        s = pA;
        pA = pA->next;
        s->next = C->next;
        C->next = s;

    }

    while (pB != NULL)
    {
        s = pB;
        pB = pB->next;
        s->next = C->next;
        C->next = s;

    }
    return OK;
}

  

原文地址:https://www.cnblogs.com/zuixime0515/p/9611522.html