双向链表的实现

双向链表简介

双向链表可以简称为双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。使用这种数据结构,我们可以不再拘束于单链表的单向创建于遍历等操作,大大减少了在使用中存在的问题。
在这里插入图片描述
在单链表中,我们有一个数据域,还有一个指针域,数据域用来存储相关数据,而指针域则负责链表之间的“联系”。而在双向链表中,如图1所示,我们需要有两个指针域,一个负责向后连接,一个负责向前连接。一个完整的双向链表中应该是头结点的pre指针指为空,尾结点的next指针指向空,其余结点前后相链。双向链表中的结点可用代码表示为:

typedef struct List{  
    int data;            //     数据域  
    struct List *next;    //  向后的指针  
    struct List *front;    //  向前的指针  
}; 

双链表的实现

1、创建双链表

对于创建双向链表,我们需要先创建头结点再逐步的进行添加,请注意,双向链表的头结点是有数据元素的,也就是头结点的data域中是存有数据的,这与一般的单链表是不同的。对于逐步添加数据,我们采取的做法是,开辟一段新的内存空间作为新的结点,为这个结点的data进行赋值,然后将已有链表的上一个结点的next指针指向自身,自身的pre指针指向上一个结点。参考代码如下:

//创建双链表  
line* initLine(line * head){  
    int number,pos=1,input_data;  
    //三个变量分别代表结点数量,当前位置,输入的数据  
    printf("请输入创建结点的大小\n");  
    scanf("%d",&number);  
    if(number<1){  
        return NULL;  
    } //输入非法直接结束  
    head=(line*)malloc(sizeof(line)); //头结点创建  
    head->pre=NULL;  
    head->next=NULL;  
    printf("输入第%d个数据\n",pos++);  
    scanf("%d",&input_data);  
    head->data=input_data;  
    line * list=head;  
    while (pos<=number) {  
        line * body=(line*)malloc(sizeof(line));  
        body->pre=NULL;  
        body->next=NULL;  
        printf("输入第%d个数据\n",pos++);  
        scanf("%d",&input_data);  
        body->data=input_data;  
        list->next=body;  
        body->pre=list;  
        list=list->next;  
    }  
    return head;  
}  

2、插入操作

对于每一次双向链表的插入操作,我们首先需要创建一个独立的结点并通过malloc操作开辟相应的空间,其次我们选中这个新创建的独立节点,将其的pre指针指向所需插入位置的前一个结点,同时,其所需插入的前一个结点的next指针修改指向为该新的结点,同理,该新的结点的next指针将会指向一个原本的下一个结点,而修改下一个结点的pre指针为指向新结点自身,这样的一个操作我们称之为双向链表的插入操作。
双向链表的实现_第1张图片

3、删除操作

如图3所示,双链表的删除操作过程为:选择需要删除的结点,选中这个结点的前一个结点,将前一个结点的next指针指向自己的下一个结点,同时,选中该节点的下一个结点,将下一个结点的pre指针修改指向为自己的上一个结点,这样产生的效果就是在进行遍历的时候直接将这一个结点给跳过了。在这样的指针修改操作之后,我们释放删除结点,归还空间给内存,这样的操作我们称之为双链表的删除操作。
双向链表的实现_第2张图片

4、遍历

如同单链表的遍历一样,利用next指针逐步向后进行索引即可,注意判断这里,我们既可以用while(list)的操作直接判断是否链表为空,也可以使用while(list->next)的操作判断该链表是否为空,其下一节点为空和本结点是否为空的判断条件是一样的效果,当然了,善用双向链表的pre指针进行有效的遍历也是值得去尝试的。

双向链表插入结点功能的实现:

#include 
#include 
//节点结构
typedef struct line {
    struct line * prior;
    int data;
    struct line * next;
}line;
//双链表的创建函数
line* initLine(line * head);
//输出双链表的函数
void display(line * head);

int main() {
    //创建一个头指针
    line * head = NULL;
    //调用链表创建函数
    head = initLine(head);
    printf("链表结构为:");
    //输出创建好的链表
    display(head);
    //显示双链表的优点
    printf("链表中第 4 个节点的直接前驱是:%d", head->next->next->next->prior->data);
    return 0;
}
line* initLine(line * head) {
	printf("输入数据中...\n");
	int data[6]={0};
	for(int i=0;i<6;i++){
		scanf("%d",&data[i]);
	} 
    line * list = NULL;
    //创建一个首元节点,链表的头指针为head
    head = (line*)malloc(sizeof(line));
    //对节点进行初始化
    head->prior = NULL;
    head->next = NULL;
    head->data = data[0];
    //声明一个指向首元节点的指针,方便后期向链表中添加新创建的节点
    list = head;
    for (int i = 1; i <= 5; i++) {

        // 请在下面的Begin-End之间补充代码,插入结点,其中结点数据为data[i]。
        /********** Begin *********/
        line *body = (line*)malloc(sizeof(line));
        body->prior=NULL;
        body->next=NULL;
        body->data = data[i];
        list->next = body;
        body->prior = list;
        list = list->next;

        /********** End **********/
    }
    //返回新创建的链表
    return head;
}
void display(line * head) {
    line * temp = head;
    while (temp) {
        //如果该节点无后继节点,说明此节点是链表的最后一个节点
        if (temp->next == NULL) {
            printf("%d\n", temp->data);
        }
        else {
            printf("%d <-> ", temp->data);
        }
        temp = temp->next;
    }
}

你可能感兴趣的:(链表,数据结构,双向链表)