20150405_链表

20150405_链表

链表(Linked list):是一种常见的数据结构,是一种线性表,但并不会按线性的存储数据,而是每个结点里存着指向下一个结点的指针。
- 优点:由于不必按顺序存储,链表在插入式的时间复杂度为O(1)。
- 缺点:查找或访问特定结点需要遍历,不支持随机查找和访问,时间复杂度O(n)。

单链表

1.结构定义

typedef struct LNode
{
    ElemType data;
    // 在此定义链表的成员
    struct Node *next;
}LNode, * Linklist;   //LNode 为链表结点的类型,Linklist为链表的类型

2.创建链表

//带头结点
void ini_linklist(Linklist *L)
{
    (*L)=(Linklist)malloc(sizeof(LNode));//这一句不可以少
    (*L)->next=NULL;
}
//在这里,创建链表,要对实参进行改变,所以对于类型linklist要传地址过来。笔者刚学习的时候对这些不太了解,所以又有如此下的一种写法,可以暂时规避这个问题。
Linklist ini_linklist(void)
{
    Linklist L;
    L=(Linklist)malloc(sizeof(LNode));
    L->next=NULL;
    return L;
}

//不带头结点
Linklist ini_linklist(void)
{
    Linklist head;
    head=NULL;  //注意这句别写错了,不然下面的都会出现问题
    return head;
}

3.头插法

顾名思义,将结点查到链表的最前头,使其成为第一个结点(若是带头结点的链表,则插入在头结点后)
说明:无论插入还是删除,我们都需要知晓我们操作结点的前驱结点的位置。

关键代码
//**带头结点的头插法**
//说明:pnew为插入结点,pre为pnew的前驱,这里应为头结点L
pnew->next=L->next;
L->next=pnew;

//**不带头结点的头插法**
//说明:笔者习惯用L表示不存储数据的头结点,对于存储数据的头结点使用head表示
pnew->next=phead;

下面附上两个实现的头插法版本

//首先是带头结点的
void head_insert(Linklist *L)
{
    Linklist pnew;
    int val;

    while(scanf("%d",&val)!=EOF)
    {
        pnew=(Linklist)malloc(sizeof(LNode));
        pnew->next=NULL; //其实这里这句可以不写,但是建议养成习惯,创建完备的结点,防止出现野指针。

        pnew->data=val;

        pnew->next=(*L)->next;
        (*L)->next=pnew;
    }
}
//不带头结点版本
void show_link(Linklist head)
{
    Linklist ptr;
    ptr=head;

    if(head==NULL)
    {
        printf("the linklist is empty\n");
        return ;
    }
    while(ptr!=NULL)
    {
        printf("%d ",ptr->data);
        ptr=ptr->next;
    }
    printf("\n");

}

4.尾插法

尾插法,插入在链表现有元素的最后一个元素(tail)之后。

关键代码
//在这里有没有头结点操作没有不同,除非使用尾插法初始化的是第一个元素,这里我们不讨论这个问题,会在下面的具体实例里处理
//说明:pnew为待插入结点,ptail为尾元素,也将成为pnew的前驱。
pnew->next=ptail->next;
ptail->next=pnew;
ptail=pnew;

下面附上两个版本的尾插法

//带头节点版本
#include "myfunc.h"
void tail_insert(Linklist *L)
{
    Linklist pnew;
    Linklist ptail;
    int val;

    ptail=(*L);
    while(ptail->next!=NULL)
    {
        ptail=ptail->next;     
    }

    //尾插
    while(scanf("%d",&val)!=EOF)
    {
        pnew=(Linklist)malloc(sizeof(LNode));
        pnew->next=NULL;

        pnew->data=val;

        pnew->next=ptail->next;
        ptail->next=pnew;
        ptail=pnew;
    }
}
//不带头结点版本
void tail_insert(Linklist *head)
{
    Linklist pnew;
    Linklist ptail;
    int val,ret;

    ptail=(*head);

    if(ptail==NULL)
    {
        ret=scanf("%d",&val);
        if(ret!=1)
            return ;
        ptail=(Linklist)malloc(sizeof(LNode));//head为空,必须为ptail分配一个地址空间,让head指向它
        ptail->data=val;
        ptail->next=NULL;
        (*head)=ptail;
    }


    while(ptail->next!=NULL)
    {
        ptail=ptail->next;     //对于非空链表,遍历到正确的ptail位置
    }

    //尾插
    while(scanf("%d",&val)!=EOF)
    {
        pnew=(Linklist)malloc(sizeof(LNode));
        pnew->next=NULL;

        pnew->data=val;

        pnew->next=ptail->next;
        ptail->next=pnew;
        ptail=pnew;
    }
}

5.删除

关键代码
//说明:ptr为操作结点指针,pre为其前驱
pre->next=ptr->next;
free(ptr);//只能释放由malloc,realloc等分配的空间,你如果不知道是否是这样的分配,最好不写。

还是惯例,附上两个删除版本

//带头结点
void delete_link(Linklist *L,int val)
{
    Linklist pre;
    Linklist ptr;
    pre=(*L);
    ptr=(*L)->next;
    if(ptr==NULL)
    {
        printf("it's an empty linklist\n");
        return ;
    }
    while(ptr!=NULL)
    {
        if(ptr->data==val)
        {
            pre->next=ptr->next;
            free(ptr);
            printf("success\n");
            return ;
        }

        pre=ptr;
        ptr=ptr->next;
    }
    printf("no such datum\n");

}
//不带头结点版本
#include "myfunc.h"
void delete_link(Linklist *head,int val)
{
    Linklist ptr,pre;
    ptr=(*head);

    if(ptr==NULL)
    {
        printf("the linklist is empty\n");
        return ;
    }
    if(ptr->data==val)
    {
        ptr=ptr->next;
        (*head)=ptr;
        return ;
    }
    pre=ptr;
    ptr=ptr->next;

    while(ptr!=NULL)
    {
        if(ptr->data==val)
        {
            pre->next=ptr->next;
            free(ptr);
            printf("success\n");
            return ;
        }
        pre=ptr;
        ptr=ptr->next;
    }
    printf("no such value\n");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值