一.循环链表

1)循环单链表

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

bool InitList(LinkList L)
{
    L=(LNode *)malloc(sizeof(LNode));
    if(L=NULL) return false;
    L->next=L;
    return true;
}

bool Empty(LinkList L)
{
    if(L->next=L) return true;
    return false;
}

bool isTail(LinkList L,LNode * p) //判断一个结点是否为尾节点
{
    return(p->next==L);
}

使用循环单链表时,如果经常需要对表头、表尾操作,可以使L指向表尾,这样找到表头、表尾的时间复杂度都是O(1)。

2)循环双链表

typedef struct LNode
{
    int data;
    LNode * next;
    LNode * prior;
}LNode,*LinkList;

bool InitList(LinkList L)
{
    L=(LNode *)malloc(sizeof(LNode));
    if(L=NULL) return false;
    L->next=L;
    L->prior=L;
    return true;
}

bool Empty(LinkList L)
{
    if(L->next=L) return true;
    return false;
}

bool isTail(LinkList L,LNode * p) //判断一个结点是否为尾节点
{
    return(p->next==L);
}

bool ListInsert(DNode * p,DNode * s) 
{
    if(p==NULL||s==NULL) return false;
    s->next=p->next; //1
    p->next->prior=s; //2 尾节点会指向头结点,不会置空,因此不需要条件判断
    s->prior=p; //3
    p->next=s;  //4  1,2必须在4前
    return true;
}


bool ListDelete(DNode * p) //删除指定结点的后继节点
{
    if(p==NULL) return false;
    DNode * q=p->next; 
    p->next=q->next;
    q->next->prior=p;
    free(q);
    return true;
}

指针类链表小结

链表类代码在编写时需要考虑三个问题:

1.如何判空,知道空的状态如何判断就知道如何初始化

2.如何判断表头,表尾,知道怎么判断表头表尾就知道怎么遍历,就知道了怎么去查找、删除、增加

3.表尾、表头是否需要特殊处理

二.静态链表

1)静态链表的定义

#define MaxSize 10

typedef struct Node
{
    int data;
    int next;
}SLinkList[MaxSize];

void InitList()
{
    SLinkList a;
}

2)静态链表的基本操作

初始化:要将a[0]置为-1;将其他空的结点游标置为-2(方便后续计算机判断哪些结点是空结点);

查找:通过游标依次遍历元素,时间复杂度为O(n)

插入:

1.找到一个空的结点用来存放元素

2.找到位序为i-1的结点

3.修改新的结点的next游标

4.修改i-1结点的next

删除:

1.找到其前驱结点

2.修改前驱结点游标

3.被删除结点的游标置为-2;

3)静态链表的优缺点

优点:增删容易,不需要大量的移动数据

缺点:查找需要遍历,容量固定