单向动态链表

单项链表的一些必要声明

#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;
typedef int ElemType;

typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode,*LinkList;

从表头到表尾逆向创建链表

图示:当链表为空时的插入情况

图示:当链表非空时的插入情况

/**
 * 从表头到表尾逆向创建链表,包含n个节点
 * 需传入表头指针的指针,因为需要对表头指针进行重定向
 * 但凡其传入的参数需要改变原值的都需要传入其指针,包括指针本身
 * 在p节点后插入in节点方法:in先和p指向相同的后继元,p再指向in
 */
void CreateList(LinkList * L, int n)
{
    *L = (LinkList)malloc(sizeof(LNode)); /* 建立头结点 */
    (*L)->next = NULL;
    LinkList in;
    for( ; n>0; n--) {
        in = (LinkList)malloc(sizeof(LNode));
        scanf("%d",&in->data); /* 创建新的节点 */
        in->next = (*L)->next; /* 总是在头结点之后插入 */
        (*L)->next = in;
    }
}

从链表中获取第 i 个元素的数据

图示:链表为空,p一开始就指向NULL,不满足直接退出

图示:链表非空,while退出条件是ji,退出时,p刚好指向第i个节点

图示:链表非空,但i的位置为处没有节点,while退出条件是p
NULL,不满足

/**
 * 从链表中获取第 i 个元素的数据。
 * 思路:可以从第一个元素开始p和j同步走,如果j=i满足退出,则p指向第i个节点
 * 若是空表,则一开始p就为空了,直接返回error
 * 若不是空表,但p到达了NULL,说明i不满足,也直接返回error
 */
Status GetElem(LinkList L, int i, ElemType *e)
{
    LinkList p = L->next;  /* p指向第一个元素 */
    int j = 1;             /* j从第 1 个元素开始 */
    while (p && j<i) {     /* 顺指针向后查找,直到p指向第i个元素或p为空 */
        p = p->next;       
        j++;
    }
    if(!p || j>i) 
        return ERROR;      /* 若p到达NULL,则必然没找到 */
    *e = p->data;
    return OK;
}

插入元素e到第i个位置

图示:链表为空时插入到第一个

图示:链表非空时,先将p索引到i-1下,然后在i-1后插入

图示:链表非空时,插入位置刚好在表尾巴

图示:链表非空时,插入位置超过了表尾

/** 
 * 在第i个位置前插入e 
 * 思路: 在第i个位置前插入,则插入后将取代i的位置,原来i的位置变成i+1
 * 需先找打i-1的位置,同样让p和j同步,j=i-1时则p刚好指向i-1的位置
 */
Status ListInsert(LinkList L, int i, ElemType e)
{
    LinkList p,s;
    p = L;      /* 从头结点开始 */
    int j=0;
    while (p && j<i-1) { /* 寻找第i-1个结点 */
        p = p->next;
        j++;
    }

    if(!p || j>i-1)     /* i小于1或者大于表长加1*/
        return ERROR;
    s = (LinkList)malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;  /* s先和p指向相同的后继元 */
    p->next = s;        /* p再指向s */
    return OK;
}

删除第i个位置的元素

图示:链表为空时没有元素可删除,显然不符合

图示:链表不为空时,p刚好索引到i-1,while退出条件是j==i-1正常删除

图示:链表不为空时,p刚好索引到i-1,while退出条件是p->next == NULL,则i处于NULL位置或更后面,i位置错误,不符合

图示:删除步骤

/**
 * 删除第i个位置的元素 
 * 思路:先索引到第i-1,这时p指向i-1,然后让q指向i临时保存起来
 * 然后断开i,即前一个不再指向它,而是指向它的后一个,最后将q释放
 */
Status ListDelete(LinkList L, int i, ElemType * e)
{
    LinkList p,q;
    p = L;
    int j=0;
    while(p->next && j<i-1) {   /* 寻找第i个结点并令p指向其前趋 */
        p = p->next;
        j++;        
    }
    if(!(p->next) || j>i-1) /* 删除位置不合理 */
        return ERROR;
    q = p->next;            /* 先让q指向p的后继元即要删除的位置,保存起来 */
    p->next = q->next;      /* 将删除的位置断链,即前一个不再指向它,而是指向它的后一个 */
    *e = q->data;
    free(q);
    return OK;
}

合并链表

图示:初始条件pa,pb指针其第一个节点,Lc和pc指向La头结点,比较 pa->data <= pb->data,满足则pc链接向pa的那个节点,同时pc移到pa位置处,pa指向下一个节点

图示:比较 pa->data <= pb->data,不满足则pc链接向pb的那个节点,同时pc移到pb位置处,pb指向下一个节点

/**
 * 归并递增链表La和Lb得到同样递增链表Lc
 * 思路:用三个指针pa,pb,pc,初始条件pa,pb指针其第一个节点,Lc和pc指向La头结点
 * 比较 pa->data <= pb->data,满足则pc链接向pa的那个节点,pa指向下一个节点
 * 让pa,pb指向剩余链表的首部,pc总是指向Lc的最后一个节点
 */
void MergeList(LinkList La, LinkList Lb, LinkList * Lc)
{
    LinkList pa,pb,pc;
    pa = La->next;  /* pa,pb分别指向第一个结点 */
    pb = Lb->next;
    *Lc = pc = La; /* 用La的头结点作为Lc的头结点 */
    while(pa && pb) {
        if(pa->data <= pb->data) {
            pc->next = pa;  /* 链接小的那个 */
            pc = pa;        
            pa = pa->next;  /* 被链接的那个指向下一个 */
        }
        else {
            pc->next = pb;
            pc = pb;
            pb = pb->next;
        }
    }
    pc->next = pa ? pa : pb; /* 插入剩余段 */
    free(Lb);               /* 释放Lb的头结点 */
}

打印链表

void printList(LinkList L)
{
    LinkList p = L->next;  /* 指向第一个节点 */
    while (p) {            /* 不是空节点 */
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");
}
posted @ 2019-10-03 10:02  wjundong  阅读(487)  评论(0编辑  收藏  举报