您的位置:首页 > 其它

双向链表的学习

2015-09-13 16:29 253 查看
本文章主要是学习双向链表的创建,显示数据,插入和删除结点,“逆置"(引号是因为双向链表有2个方向,所以我们要实现逆置,只需要利用它的前指针即可)

我们还是用代码来说明吧

1.结构体的创建

typedef struct double_link
{
    int data;//数据域
    struct double_link *pre;//指针域,存放前一个数据地址
    struct double_link *next;//指针域,存放后一个数据地址
}node;


双向链表比单向链表多了一个指针域就是代码中的 pre指针,其实这些名称是为了我们好理解,指针只是存放地址,它不会知道哪个是前哪个是后,只是我们创建了这样一个结构体,给了它2个指针域,可以存放2个地址,就这样它就可以前后想通,即可以存放它前一个数据的地址,又可以存放后一个数据的地址,这样就方便我们去查询。

2.双向链表的创建

node * creat_double_link(int n)
{
    node *head,*l,*p;
    int i;
    head=(node *)malloc(sizeof(node));
    head->next=NULL;
    head->pre=NULL;
    p=head;

    for(i=0;i<n;i++)
    {
        l=(node*)malloc(sizeof(node));
        printf("intput the %d data:\n",i+1);
        scanf("%d",&l->data);
        p->next=l;
        l->pre=p;
        p=l;
    }
    p->next=NULL;
    return head;
}


我们还是创建了带头结点的双向链表,头结点的前指针指向NULL.

这里我就不画图了,原理跟单向链表一样,只是多了一个指针域,例如:p->next=l;这个代码是单向链表建立联系的关键,这里我们多了一句 l->pre=p,这样就成了一个双向链表,新建的l结点可以查找它上一个结点的地址了,而不是只有它下一个结点的地址。

3.链表数据显示

void printlist(node * head)
{
    node *p;
    int i=1;
    p=head->next;

    while(p!=NULL)
    {
        printf("the (%d) data=%d\n",i,p->data);
        i++;
        p=p->next;
    }

}


这个没什么好说的,还是和单向链表一样

4.双向链表的结点插入

void insert_list(node *head,int i)
{
    node * new,*p;
    p=head;
    int j=0;

    while(j<i)//遍历结点,寻找我们要插的结点的位置,这里是在这个结点后面插,这里还是跟我单向链表一样,你输入i=1的时候就是第一个数据结点,如果想在头结点插的话还是输入i=0;
    {
        p=p->next;
        j++;
    }

    new=(node*)malloc(sizeof(node));
    printf("input the data:\n");
    scanf("%d",&new->data);

    if(p->next!=NULL)//这里是判断我们插入的结点是不是最后一个结点,如果不这样做的话当我们插入最后结点后面的时候报出现段错误,原因也很好分析,因为如果是最后一个结点,那么p->next就是null了,一个空指针你去操作它肯定有问题的
    {
        p->next->pre=new;
        new->next=p->next;
        p->next=new;
        new->pre=p;
    }
    else//如果是最后一个结点就这样操作
    {
        new->pre=p;
        p->next=new;
        new->next=NULL;
    }
    
}
链表的插入的关键就是下面:

p->next->pre=new;

new->next=p->next;

p->next=new;

new->pre=p;

这就是实现插入的方法,其实方法有很多很多,关键的问题是你要知道你是操作的地址,所以我们必须得保存一个关键地址就是p->next,这个地址必须得最后操作,如果你这样写:



p->next=new;

new->pre=p;

p->next->pre=new;

new->next=p->next;

前面2句你是建立了这个新结点和p结点的联系,但是当你去想建立新结点和p后面那个结点的联系的时候(后面2句),你会发现已经找不到地址了,因为p结点和它后面的那个结点的联系你已经切断了,找不到它后面结点的位置了,所以切记,这里就是双向链表中插入的一个陷阱。

如果你想这么做也行,你就得再建立一个临时指针,去存放p->next的地址,把p和它原来后面的那个结点的地址保存下来,这样你就可以先建立p和新结点的联系了。

5.双向链表的删除
void delete_list(node * head,int i)
{
    node * p,*q;

    int j=0;

    p=head;

    while(j<i)
    {
        p=p->next;
        j++;
    }

    if(p->next!=NULL)
    {
        q=p->next;
        q->pre=p->pre;
        p->pre->next=q;
    }
    else
    {
        p->pre->next=NULL;

    }
    free(p);

}
这里是先找到我们要删除的结点p,然后再将p结点后面一个结点的地址赋值给q,再建立q和p前面一个结点的联系即可,最后free掉p即可。

方法是很多种的,这里只是我的一种方法,你也可以找到p 前面那个结点的地址,再和p后面的那个结点建立联系,大同小异。

6.双向链表的”逆置“

void reverse_display_list(node * head)
{
    node *p;
    int i=1;

    p=head;

    while(p->next!=NULL)
    {
        p=p->next;
    }

    while(p->pre)
    {
        printf("the (%d) data=%d\n",i,p->data);
        i++;
        p=p->pre;
    }

}
这里我只是先遍历到最后一个结点然后用它的pre指针一个个显示数据

最后是我们的main函数
void main()
{
    node * head;

    int n,i;

    printf("intput the number of the data:\n");
    scanf("%d",&n);
    head=creat_double_link(n);
    printlist(head);
    printf("input the position of the insert the list\n");
    scanf("%d",&i);
    insert_list(head,i);
    printlist(head);
    printf("input the position of the delete the list\n");
    scanf("%d",&i);
    delete_list(head,i);
    printlist(head);
    printf("the reverse_display_listlist:\n");
    reverse_display_listlist(head);
}
最后上图

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: