Wangdao postgraduate entrance examination data structure--3. Double linked list

Table of contents

1 Introduction

2. Code Difficulties

2.1 Insertion and deletion of double linked list

3. Code function

3.1 Double linked list structure definition

3.2 Double linked list initialization function

3.3 Double linked list insertion

3.4 Double linked list node deletion

3.5 Traversal of double linked list

4. All codes 


1 Introduction

Date: 2023.6.21

Book: 2024 Data Structure PubMed Review Guide (Wang Dao PubMed Series)

Content: implementation of double-linked list, structure definition, initialization, creation of new nodes, head insertion and tail insertion, query, insertion in bit order, deletion of specified nodes, output of single-linked list


2. Code Difficulties

2.1 Insertion and deletion of double linked list

Insert the s node after the p node,

The sequence of statements in the above figure is not unique, but it is not arbitrary either.

Steps ① and ② must be before step ④ ,

Otherwise, the pointer of the successor node of p will be lost, causing the insertion to fail.
To deepen understanding, readers can draw schematic diagrams on paper.

Here, ①② has no order requirement
. If the question is changed to request to delete the predecessor node *p of node
q, please think about the specific operation steps.


3. Code function

3.1 Double linked list structure definition

#include <stdio.h>
#include <stdlib.h>

//C语言自定义bool操作
#define bool char
#define false 0
#define true 1

/*数据元素类型*/
typedef int ElemType;

/*双链表结构体定义*/
typedef struct DNode        //定双链表结点类型
{
    ElemType data;          //每个结点存放一个数据元素
    struct DNode *next;     //指针指向下一节点
    struct DNode *prior;    //指针指向上一节点
}DNode,*DLinkList;


3.2 Double linked list initialization function

/*双链表初始化函数*/
DLinkList DLinkListInit()
{
    //[1]申请空间
    DLinkList L = (DLinkList)malloc(sizeof(DLinkList));
    //[2]安排指针
    L->next = NULL;
    L->prior = NULL;
    //[3]返回头节点
    return L;
}

3.3 Double linked list insertion

/*双链表的插入操作*/
//【1】双链表新节点的创建,返回新节点指针
DNode* CreateNewDNode(ElemType data){
    //[1]为新节点分配空间,并判断是否分配成功
    DNode* newNode = (DNode*)malloc(sizeof(DNode));
    if(!newNode){
        printf("分配空间失败,请检查内存!\n");
        return NULL;
    }
    //[2]初始化新节点
    newNode->data = data;
    newNode->next = NULL;
    newNode->prior = NULL;
    //[3]返回节点地址
    return newNode;
}


//【2】双链表节点定位----按位序号查询,返回需要查找的节点的指针
DNode* GetElem(DLinkList L, int i){
    //[1]判空
    if(L->next == NULL) {printf("这是空表!"); return L;}
    //[2]生成指向目标节点的指针p
    DNode* p = L->next;
    //[3]如果i = 0
    if(i < 1){
        p = L;
        return p;
    }
    //[4]开始循环定位
    while (p->next != NULL && i != 1){
        p = p->next;
        i--;
    }
    //[5]返回节点
    if(i != 1)
    printf("没有这个节点,返回链表的最后一位.\n");
    return p;
}


//【3】双链表节点定位----按内容值查询,返回需要查找的节点的指针
DNode* LocateElem(DLinkList L,ElemType e){
    //[1]判空
    if(L->next == NULL) {printf("这是空表!"); return L;}
    //[2]生成指向目标节点的指针p
    DNode* p = L->next;
    //[3]开始循环定位
    while (p->next != NULL && p->data != e){
        p = p->next;
    }
    //[4]返回节点
    if(p->data != e)//排除最后一位元素是目标元素的情况
    printf("没有这个节点,返回链表的最后一位.");
    return p;
}


//【4】双链表的插入操作
//在第i位插入新元素,如果第i位不存在,则插入在表尾
bool DLinkListInsert(DLinkList L,int i,ElemType e){
    //[0]程序健壮性增强
    if(i < 1){
        printf("输入出错!");
        return 0;
    }
    //[1]建立新元素节点
    DNode* s = CreateNewDNode(e);
    if(s == NULL) return 0;

    //[2]生成指向待插入位置的指针p
    DNode* p = GetElem(L,i-1);
    //[3]插入新节点

    s->next = p->next;
    if(p->next != NULL)
        p->next->prior = s;
    s->prior = p;
    p->next = s;
    //[4]插入成功,返回结果
    return 1;
}

3.4 Double linked list node deletion

//按位删除
bool DLinkLisDelete(DLinkList L,int i){
    //[1]判空
    if(L->next == NULL){
        printf("表空,无删除元素\n");
        return false;
    }

    //[2]定位,找到待删除元素的前一位*p和待删除元素*q
    DNode* p = GetElem(L,i-1);
    if(p == NULL) return false;
    DNode* q = p->next;
    if(q == NULL) return false; //*p没有后继结点
    //[3]执行删除操作
    p->next = q->next;
    if(q->next != NULL)         //*q不是最后一位元素
        q->next->prior = p;
    free(q);
    return true;
    //没有q的写法
    // if(p->next == NULL) false;  //最后一位,没有后继
    // p->next = p->next->next;
    // if(p->next->next != NULL)   //待删除结点不是最后一个节点
    //     p->next->next->prior = p;
    // free(p);              //释放结点空间
    // return true;
}
//删除双链表
void DestoryList(DLinkList L){
    while (L->next != NULL){
        DLinkLisDelete(L,1);
    }
}

3.5 Traversal of double linked list

/*双链表的遍历*/
int PrintDLinkList(DLinkList L){
    //[1]判空
    if (L == NULL){
        printf("该链表不存在\n");
        return 0;
    }
    
    if(L->next == NULL){
        printf("这是空表!没有需要打印的元素");   
        return 0;
    }
    //[2]生成当前要打印的元素位置的指针p
    DNode* p = L->next;
    //[3]遍历打印
    int i = 0;
    while (p!= NULL){
        i++;
        printf("第%d个元素的内容值为:%d\n",i,p->data);
        p = p->next;
        
    }
    printf("打印结束,共%d个链表结点.\n",i);
    return 0;
}


4. Complete the code 

#include <stdio.h>
#include <stdlib.h>

//C语言自定义bool操作
#define bool char
#define false 0
#define true 1

/*数据元素类型*/
typedef int ElemType;

/*双链表结构体定义*/
typedef struct DNode{        //定双链表结点类型
    ElemType data;          //每个结点存放一个数据元素
    struct DNode *next;     //指针指向下一节点
    struct DNode *prior;    //指针指向上一节点
}DNode,*DLinkList;

/*双链表初始化函数*/
DLinkList DLinkListInit(){
    //[1]申请空间
    DLinkList L = (DLinkList)malloc(sizeof(DLinkList));
    //[2]安排指针
    L->next = NULL;
    L->prior = NULL;
    //[3]返回头节点
    return L;
}

/*双链表的插入操作*/
//【1】双链表新节点的创建,返回新节点指针
DNode* CreateNewDNode(ElemType data){
    //[1]为新节点分配空间,并判断是否分配成功
    DNode* newNode = (DNode*)malloc(sizeof(DNode));
    if(!newNode){
        printf("分配空间失败,请检查内存!\n");
        return NULL;
    }
    //[2]初始化新节点
    newNode->data = data;
    newNode->next = NULL;
    newNode->prior = NULL;
    //[3]返回节点地址
    return newNode;
}
//【2】双链表节点定位----按位序号查询,返回需要查找的节点的指针
DNode* GetElem(DLinkList L, int i){
    //[1]判空
    if(L->next == NULL) {printf("这是空表!"); return L;}
    //[2]生成指向目标节点的指针p
    DNode* p = L->next;
    //[3]如果i = 0
    if(i < 1){
        p = L;
        return p;
    }
    //[4]开始循环定位
    while (p->next != NULL && i != 1){
        p = p->next;
        i--;
    }
    //[5]返回节点
    if(i != 1)
    printf("没有这个节点,返回链表的最后一位.\n");
    return p;
}
//【3】双链表节点定位----按内容值查询,返回需要查找的节点的指针
DNode* LocateElem(DLinkList L,ElemType e){
    //[1]判空
    if(L->next == NULL) {printf("这是空表!"); return L;}
    //[2]生成指向目标节点的指针p
    DNode* p = L->next;
    //[3]开始循环定位
    while (p->next != NULL && p->data != e){
        p = p->next;
    }
    //[4]返回节点
    if(p->data != e)//排除最后一位元素是目标元素的情况
    printf("没有这个节点,返回链表的最后一位.");
    return p;
}
//【4】双链表的插入操作
//在第i位插入新元素,如果第i位不存在,则插入在表尾
bool DLinkListInsert(DLinkList L,int i,ElemType e){
    //[0]程序健壮性增强
    if(i < 1){
        printf("输入出错!");
        return 0;
    }
    //[1]建立新元素节点
    DNode* s = CreateNewDNode(e);
    if(s == NULL) return 0;
    //[2]生成指向待插入位置的指针p
    DNode* p = GetElem(L,i-1);
    //[3]插入新节点
    s->next = p->next;
    if(p->next != NULL)
        p->next->prior = s;
    s->prior = p;
    p->next = s;
    //[4]插入成功,返回结果
    return 1;
}

/*双链表的遍历*/
int PrintDLinkList(DLinkList L){
    //[1]判空
    if (L == NULL){
        printf("该链表不存在\n");
        return 0;
    }
    
    if(L->next == NULL){
        printf("这是空表!没有需要打印的元素");   
        return 0;
    }
    //[2]生成当前要打印的元素位置的指针p
    DNode* p = L->next;
    //[3]遍历打印
    int i = 0;
    while (p!= NULL){
        i++;
        printf("第%d个元素的内容值为:%d\n",i,p->data);
        p = p->next;
        
    }
    printf("打印结束,共%d个链表结点.\n",i);
    return 0;
}

/*双链表的删除操作*/
//按位删除
bool DLinkLisDelete(DLinkList L,int i){
    //[1]判空
    if(L->next == NULL){
        printf("表空,无删除元素\n");
        return false;
    }
    //[2]定位,找到待删除元素的前一位*p和待删除元素*q
    DNode* p = GetElem(L,i-1);
    if(p == NULL) return false;
    DNode* q = p->next;
    if(q == NULL) return false; //*p没有后继结点
    //[3]执行删除操作
    p->next = q->next;
    if(q->next != NULL)         //*q不是最后一位元素
        q->next->prior = p;
    free(q);
    return true;
    //没有q的写法
    // if(p->next == NULL) false;  //最后一位,没有后继
    // p->next = p->next->next;
    // if(p->next->next != NULL)   //待删除结点不是最后一个节点
    //     p->next->next->prior = p;
    // free(p);              //释放结点空间
    // return true;
}
//删除双链表
void DestoryList(DLinkList L){
    while (L->next != NULL){
        DLinkLisDelete(L,1);
    }
}




int main(){
    //[1]不带头结点的声明定义双链表
    DLinkList L = NULL;
    //[2]带头节点的声明定义双链表
    L = DLinkListInit();
    //[3]测试:插入结点
    DLinkListInsert(L,1,1);
    DLinkListInsert(L,1,2);
    DLinkListInsert(L,1,3);
    DLinkListInsert(L,1,4);
    DLinkListInsert(L,1,5);
    DLinkListInsert(L,1,6);
    DLinkListInsert(L,1,7);
    DLinkListInsert(L,1,8);
    DLinkListInsert(L,1,9);
    DLinkListInsert(L,1,10);
    DLinkListInsert(L,1,11);
    DLinkListInsert(L,1,12);
    PrintDLinkList(L);
    DLinkListInsert(L,4,888);
    DLinkListInsert(L,7,1022);
    DLinkListInsert(L,9,963);
    DLinkListInsert(L,11,8522);
    DLinkListInsert(L,100,150);
    DLinkListInsert(L,4,12000);
    DLinkListInsert(L,8,17869);
    PrintDLinkList(L);
    DLinkLisDelete(L,8);
    PrintDLinkList(L);
    DestoryList(L);
    L = NULL;
    PrintDLinkList(L);
    // DNode* node = LocateElem(L,150);
    // printf("Node.data = %d",node->data);
return 0;
}

Guess you like

Origin blog.csdn.net/qq_58602552/article/details/131333513