20150405_链表

来源:互联网 发布:linux jenkins svn 编辑:程序博客网 时间:2024/05/29 13:11

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的前驱,这里应为头结点Lpnew->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");}
0 0
原创粉丝点击