数据结构与算法(3)- 双向链表

337 阅读5分钟

一、双向链表

1、双向链表结构

1)双向链表结构定义

#define ERROR 0;
#define OK 1;

typedef int ret; //函数返回类型
typedef int Element;

//定义结点
typedef struct Node {
    Element data;
    Node *prior;
    Node *next;
}Node;

typedef Node *LinkList;

2)创建双向链表

ret createLise(LinkList *l) {
    //创建指向头结点的链表
    *l = (LinkList)malloc(sizeof(Node));
    if(*l == NULL) return ERROR;
    (*l)->next = NULL;
    (*l)->prior = NULL;
    (*l)->data = -1;
    
    //新增数据
    LinkList p = *l; 
    for(int i = 1, i <= 10; i++) {
        //创建一个新结点
        LinkList newNode = (LinkList)malloc(sizeof(Node));
        if(newNode == NULL) return ERROR;
        
        newNode->data = i;
        newNode->next = NULL;
        //newNode的前驱是p;
        newNode->prior = p;
        //p的后继是newNpde
        p->next = newNpde;
        //更新p 的值,p指向p的后继
        p = p->next;
    }
    return YES;
}

3)打印循环链表的元素

void displayList(LinkList l) {
    //因为第一个结点为头结点
    linkList p = l->next;
    if(p == NULL) return NULL;
    
    while(p) {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("\n");
}

4)双向链表插入元素

int listInsert(LinkList *l, int place, Element e) {
    LinkList p, newNode;
    int i;
    if (place < 1) return ERROR;
    
    //创建新结点
    newNode = (LinkList)malloc(sizeof(Node));
    if (newNode == NULL) return ERROR;
    newNode->data = e;
    newNode->next = NULL;
    newNode->prior = NULL;
    
    //p 赋值为头结点
     p = *l;
    //找到 place - 1 位置的结点
    for(i = 1; i < place && p; i++) {
        p = p->next;
    }
    
    //说插入的位置越界
    if(p == NULL) return ERROR;
    
    //如果为最后一个元素
    if (p->next == NULL) {
        newNode->prior = p;
        p->next = newNode;
    } else {
        //p->next 的前驱赋值 newNode;
        p->next->prior = newNode;
        //newNode 的 next 赋值为p原来的next;
        newNode->next = p->next;
        //新结点的前驱赋值为p
        newNode->prior = p;
        //p->next赋值为新结点
        p->next = newNode;
    }
   return YES; 
}

5)删除双向链表指定位置上的结点

ret listDelete(LinkList *l, int place) {
    LinkList p;
    p = *l;
    
    if(*l == NULL) 
    printf("链表以为空!");
    
    if(place > 1);
    printf("删除位置不合法!");
    
    //找到 place - 1 位置的结点
    for (int i = 1; i < place; i++) {
        p = p->next;
    }
    如果第place 位置的结点不存在,或者要删除的位置不合法返回ERROR
    if(p == NULL || i>place) {
        return ERROR;
    }
    //指向要
    LinkList delNode = p->next;
    
    p->next = delNode->next;
    
    if (delNode->next != NULL) {
        delNode->next->prior = p;
    }
    free(delNode);
    return YES;
}

6)删除双向链表指定值的结点

删除思想跟第五差不多,但是实现方法有差异

ret delList(LinkList *l, Element e) {
    LinkList p;
    p = (*l)->next;
    
    if (p == NULL) {
        printf("链表以为空!");
    }
    
    while (p) {
        //判断当前结点是否是要删除的结点
        if (p->data == e) {
            //将要删除的结点前驱结点的next赋值为要删除结点的后继结点
            p->prior->next = p->next;
            //判断要删除结点的后继结点是否存在
            if( p->next != NULL)
            //将要删除结点的后继结点的前驱赋值为要删除结点的前驱结点
            p->next->prior = p->prior;
            //释放要删除的结点
            free(p);
            break;
        }
        p = p->next;
    }
    return YES;
}

7)在双向链表中查找元素

int findElement(LinkList l, Element e) {
    int i = 1;
    linkList temp;
    temp = l->next;
    while(temp) {
        if (temp == e) {
            break;
        }
        temp = temp->next;
        i++;
    }
    return i;
}

8)在双向链表中更新结点

ret = replaceLinkList(LinkList *l, int index, Element e) {
    LinkList temp = (*l)->next;
    for (int i = 1; i<index; i++) {
        temp = temp->next;
    }
    temp->data = e;
    
    return YES;
}

2、双向循环链表

1)双向链表结构定义

#define ERROR 0;
#define OK 1;

typedef int ret; //函数返回类型
typedef int Element;

//定义结点
typedef struct Node {
    Element data;
    Node *prior;
    Node *next;
}Node;

typedef Node *LinkList;

2)双向循环链表初始化

ret createList(LinkList *l) {
    //创建一个头结点
    *l = (LinkList)malloc(sizeof(Node));
    if(*l == NULL) return ERROR;
    (*l)->data = -1;
    (*l)->next = NULL;
    (*l)->prior = NULL;
    
    LinkList p = *l;
    //增加结点
    for(int i = 1; i < 10; i++) {
        LinkList newNode = (LinkList)malloc(sizeof(Node));
        if(newNode == NULL) continue;
        p->next = newNode;
        newNode->data = i;
        newNode->next = *l;
        newNode->prior = p;
        
        p = p->next;
    }
    return YES;
}

3)双向循环链表插入元素

/*当插入位置超过链表长度则插入到链表末尾*/
ret listInsert(LinkList *l, int place, Element e) {
    LinkList p, newNode;
    int i = 1;
    //双向链表为空
    if (*l == NULL) return ERROR;
    //插入位置非法
    if (place < i) return ERROR;
    //找到 place - 1 位置的结点
    for(p = *l; i< place, p->next != *l; p = p->next, i++;)
    //创建新结点
    newNode = (LinkList)malloc(sizeof(Node));
    //创建失败
    if(newNode == NULL) return ERROR;
    newNode->data = e;
    //新结点的next 指向 p->next
    newNode->next = p->next;
    //新结点的前驱指向 p
    newNode->prior = p;
    //p 的后继指向新结点
    p->next = newNode;
    //判断newNode是否为最后一个结点
    if(*l != newNode->next) {
        //新结点后继结点的前驱赋值为 新结点
        newNode->next->prior = newNode;
    } else {
        //将首结点的前驱赋值为新结点
        (*l)->prior = newNode;
    }
    
}

4)遍历双向循环链表

void displayList(LinkList l) {
    if (l == NULL) {
        printf("链表为空!");
        return;
    }
    printf("双向循环链表内容:  ");
    LinkList p = p->next;
    while(p != l) {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("\n");
}

5)双向循环链表删除结点

ret delList(LinkList *l, int index, Element *e) {
    LinkList p;
    p = (*l)->next;
    if((*l)->next == l) {
        printf("链表为空!");
        return ERROR;
    }
    
    //如果删除到只剩首元结点,直接将链表置空
    if(p->next == *l) {
        free(*l)
        (*l) = NULL;
        return YES;
    }
    
    int i = 1;
    if(index < i) {
        printf("删除位置不合法!");
    }
    while(i < index) {
        p = p->next;
    }
    
    *e = p;
    //要删除结点的后继的前驱赋值为要删除结点的前驱
    p->next->prior = p->prior;
    //要删除的结点的前驱的后继赋值为要删除结点的后继
    p->prior->next = p->next;
    free(p);
    return YES;
}