一、链表的概念
 
   链表:是用一组地址任意的存储单元存放线性表的各个数据元素,通过保存直接后继的存储位置来表示元素之间的逻辑关系;
   结点:是链表的基本存储单位,每个结点在链表中使用一块连续的存储空间,而相邻结点之间不必使用连续的存储空间;
   结点由数据域和指针域构成。

   表中所有的数据元素都分别保存在具有相同数据结构的结点中,结点与数据元素是一一对应。
 
   头指针:以线性表中第一个数据元素的存储地址作为线性表的地址,称作线性表的头指针。
 
   头结点:有时为了操作方便,在第一个结点之前虚加一个“头结点”,不存放数据元素,以指向头结点的指针为链表的头指针。
 
二、单链表
    单链表的节点定义:   
  
typedef int elemtype;
typedef struct LNode
{
    elemtype data;
    struct LNode *next;
}LinkList,*pLinkList;
(一)带头结点的单链表
     头结点的数据域可以不存任何信息,也可根据需要存储线性表的长度等附加信息;
     头结点的指针域指向第一个结点(第一个元素的存储位置);
     单链表的头指针指向头结点;
     若单链表为空,则头结点的指针域为“空”。
     带头结点的单链表的基本操作:
#include<stdio.h>
#include<stdlib.h>
//单链表存储结构(一个节点的结构)

typedef int elemtype;
typedef enum
{
    OK,
//0


    TRUE,
//1


    FALSE,
//2


    ERROR,
//3


    OVERFLOW
//4


}Status;


typedef struct LNode
{
    elemtype data;
    struct LNode *next;
}LinkList,*pLinkList;

/*带头节点的单链表初始化*/
void InitList(pLinkList L)
{
    L=(pLinkList)malloc(sizeof(elemtype));
    if(!L)
        exit(OVERFLOW);
    L->next = NULL;
}

/*销毁带头节点的单链表*/
void DestroyList(pLinkList L)
{
    pLinkList q;
    while(L)
//直到L=NULL

    {
        q = L->next;
        free(L);
        L = q;
    }
}

/*将带头结点的单链表重置为空表,只留一个头结点*/
void ClearList(pLinkList L)
{
    pLinkList p = L->next;
    L->next = NULL;
    DestroyList(p);
}

/*判断带头结点的单链表是否为空表,是返回TRUE,否返回FALSE*/
Status ListEmpty(pLinkList L)
{
    if(L->next)
        return FALSE;
    else
        return TRUE;
}

/*返回带头节点单链表中数据元素的个数*/
int ListLength(pLinkList L)
{
    int i=0;
    pLinkList p;
    p = L->next;
    while(p)
    {
        i++;
        p = p->next;
    }
    return i;
}

/*当第i个元素存在时,从带头结点的单链表中返回第i个元素到e中,并返回ok,否则返回error*/
Status GetElem(pLinkList L,int i,elemtype *e)
{
    int j = 1;
    pLinkList p = L->next;
    while(p && i>j)
//P指向第i个元素的位置

    {
        j++;
        p = p->next;
    }
    if(!p || j>i)
//i大于表长或i<1;

        return ERROR;
    *e = p->data;
    return OK;
}

/*在带头结点的单链表中的第i个位置之前插入元素e*/
Status ListInsert(pLinkList L,int i,elemtype e)
{
    int j = 0;
//计数器

    pLinkList s,p = L;
//p指向表头

    while(p && j<i-1)
//由于是单向链表,必须先寻找到i-1个位置

    {
        j++;
        p = p->next;
    }
    if(!p || j>i-1)
//i大于(表长+1)或小于1

        return ERROR;
    s = (pLinkList)malloc(sizeof(LinkList));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return OK;
}

/*从带头节点的单链表中,删除第i个元素,并由e返回其值*/
Status ListDelete(pLinkList L,int i,elemtype *e)
{
    int j = 0;
    pLinkList s,p = L;
    while(p->next && j<i-1)
//p指向第i-1个位置

    {
        j++;
        p = p->next;
    }
    if(!(p->next) || j>i-1)
     return ERROR;
    s = p->next;
    p->next = s->next;
    *e = s->data;
    free(s);
    return OK;
}

/*若cur_e是带头结点单链表内的数据元素,且不是第一个,则用pre_e返回它的前驱*/
Status PriorElem(pLinkList L,elemtype cur_e,elemtype *pre_e)
{
    pLinkList q,p=L->next;
    while(p->next)
    {
        q = p->next;
        if(q->data == cur_e)
        {
            *pre_e = p->data;
            return OK;
        }
        p = q;
    }
    return OK;
}

/*若cur_e是带头结点单链表内的数据元素,且不是最后一个,则用next_e返回他的后继*/
Status NextElem(pLinkList L,elemtype cur_e,elemtype *next_e)
{
    pLinkList p=L->next;
    while(p->next)
    {
        if(p->data == cur_e)
        {
            *next_e = p->next->data;
            return OK;
        }
        p = p->next;
    }
    return ERROR;
}

/*返回带头结点的单链表内第一个与e满足compare()关系的数据元素的的为序*/
int LocateElem(pLinkList L,elemtype e,Status(*compare)(elemtype,elemtype))
{
    int i=0;
    pLinkList p = L->next;
    while(p)
    {
        i++;
        if(compare(p->data,e))
            return i;
        p = p->next;
    }
    return -1;
}

/*依次对带头结点单链表中的每一个元素数据调用visit()函数*/
void ListTraverse(pLinkList L,void(*visit)(elemtype *))
{
    pLinkList p = L->next;
    while(p)
    {
        visit(&(p->data));
        p = p->next;
    }
}

其他操作:
/*用键盘输入N个元素,从表头插入这N个元素(逆位序),建立带头结点的单链表*/
void CreateList(pLinkList L,int n)
{
    int i;
    pLinkList p;
    L=(pLinkList)malloc(sizeof(LinkList));
    L->next = NULL;
    printf("请输入%d个数据\n",n);
    for(i=0;i<n;i++)
    {
        p=(pLinkList)malloc(sizeof(LinkList));
        scanf("%d",&p->data);
        p->next = L->next;
        L->next = p;
    }
}

/*用键盘输入N个元素,从表尾插入这N个元素(正位序),建立带头节点的单链表*/
void CreateList1(pLinkList L,int n)
{
    int i;
    pLinkList p,q;
    L=(pLinkList)malloc(sizeof(LinkList));
    L->next = NULL;
    q = L;
    printf("请输入%d个数据\n",n);
    for(i=0;i<n;i++)
    {
        p=(pLinkList)malloc(sizeof(LinkList));
        scanf("%d",&p->data);
        q->next = p;
        q = p;
    }
    p->next = NULL;
}

/*带头结点单链表的归并
单链线性表La和Lb的元素按值非递减排列
归并La和Lb得到新单链表Lc,其元素也按值非递减排列
摧毁了La,Lb,得到了Lc
*/

void MergeList_L(LinkList*La, LinkList*Lb, LinkList*Lc)
{
    pLinkList pa=La->next,pb=Lb->next,pc;
//pa、pb指向表A、B的第一个结点

    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的头结点

Lb = NULL;
//Lb不再指向任何节点

}