线性表专题3 双向链表和双向循环链表 - 2020-4-3- 算法 03

486 阅读4分钟

双向链表

双向链表

  • prior 前驱
  • data 数据域
  • next 后继

通过上图可以发现,使用带有头结点的双向链表在修改的过程时会显得更加方便

typedef struct Node{
    ElementType data;
    struct Node *prior;
    sturct Node *next;
}Node;
typedef struct Node *LinkList;

1.双向链表的创建

Status createLinkList(LinkList *L){
    *L = (LinkList)malloc(sizeof(Node));
    if(*L == NULL) return ERROR;
    //1 要先将头结点置空并将数据设为-1
    (*L)->prior = NULL;
    (*L)->next = NULL;
    (*L)->data = -1;
    //2 新增结点 (使用尾插法)
    LinkList p = *L;
    for(int i=0;i < 10;i++){
        //1 创建结点temp
        LinkList temp = (LinkList)malloc(sizeof(Node));
        if(temp == NULL) return ERROR;
        temp -> prior = NULL;
        temp -> next = NULL;
        temp -> data = i;
        //2 temp 创建双向链表的关系
        p->next = temp;
        temp ->prior = p;
        p = p->next;
    }
}
//展示
void display(LinkList L){
    LinkList temp = L->next; //跳过为空的头结点
    if(temp == NULL){
        printf("打印的双向链表为空\n");
        return;
    }
    while(temp){
        printf("%d ",temp->data);
        temp = temp->next;
    }
    printf("\n");
}

2.双向链表的插入

4个步骤
  • 先找到要插入的前一个结点,B的前驱指向CC
  • CC的后继指向B
  • A的后继指向CC
  • CC的前驱指向A 三步四步可以调换顺序

//L 链表 i 位置 data 数据
Status ListInsert(LinkList *L,int i,ElementType data){
    //1 不可以插在头结点前
    if(i < 1) return ERROR;
    //2 新建结点
    LinkList temp = (LinkList)malloc(sizeof(Node));
    temp->data = data;
    temp->next = NULL;
    temp->prior = NULL;
    //3
    LinkList p = (*L);
    //插入位置的前一个位置
    for(int j=1;j < i && p;j++){ //找位置 p越界就会for循环break
        p=p->next; 
    }
    //4. 如果i超过链表长度 p会指向null
    if(p == NULL) return ERROR;
    // 5 结点插入到链表中
    if(p->next == NULL){ //插入到链表最后一个结点
        p->next = temp;
        temp -> prior = p;
        
    }else{
        p->next->prior = temp;
        temp->next = p->next;
        p->next = temp;
        temp->prior = p;
    }
    
    
    return OK;
}

3.双向链表的删除

  • 创建临时指针指向要删除的结点
  • A结点的后继指向C
  • C的前驱指向A
  • 释放B
//指定位置 L 链表 i删除的位置 e 要带回删掉的结点的数据
Status ListDelete(LinkList *L,int i,ElementType *e){
    int k =1;
    LinkList p = (*L);
    if(*L == NULL) return ERROR;
    while(k<i&& p!=NULL){
        p = p->next;
        k++;
    }
    if(k>i && p== NULL) return ERROR; //如果i输入的不合法
    LinkList delTemp = p->next;
    *e = delTemp->data;
    p->next = delTemp ->next;
    if(delTemp->next!=NULL){ //不是尾结点的情况下
        delTemp->next->prior = p;
    }
    free(delTemp);
    return OK;
}
//根据指定结点的数据来删除结点
Status LinkListDeleteVal(LinkList *L,int data){
    LinkList p = (*L)->next;
    while(p){
        if(p->data == data){
            p->prior ->next = p->next;
            if(p->next != NULL){
                p->next->prior = p->prior;
            }
            free(p);
            break;
        }
        p = p->next;
    }
    return OK;
}

4.双向链表的查找

//查找
int selectElem(LinkList L,ElementType elem){
    LinkList p = L->next;
    int i = 1;
    while (p) {
        if (p->data == elem) {
            return i;
        }
        
        i++;
        p = p->next;
    }
    
    return  -1;
}

5.双向链表的替换

//更新
Status replaceLinkList(LinkList *L,int index,ElemType newElem){
   LinkList p = (*L)->next;
    
    for (int i = 1; i < index; i++) {
        p = p->next;
    }
    
    p->data = newElem;
    return OK; 
}

双向循环链表

首节点和尾结点需要一些判断 判断循环结束就是p->next = *L;

1.双向循环链表的创建

Status initLinkList(LinkeList *L){
    *L = (LinkList)malloc(sizeof(Node));
    if(*L == NULL) return ERROR;
    (*L)->next = (*L);
    (*L)->prior = (*L);
    (*L)->data = -1;
    return OK;
}

2.双向循环链表的插入

//需要判断是否为尾,但是不需要判断是否是头 
Status LinkListInsert(LinkList *L,int index,ElemType e){
    LinkList p = *L;
    int i = 1;
    if(*L == NULL) return ERROR; //如果要插入的为空就报错
    while(i < index){
        p = p->next;
        i++;
    }
    if(i > index) return ERROR;
    LinkList temp = (LinkList)malloc(sizeof(Node));
    if(temp == NULL) return ERROR;
    temp ->data = e;
    temp->prior = p;
    temp->next = p->next;
    p->next = temp;
    if(*L != temp->next){ //如果不是最后一个结点
        temp ->next ->prior = temp;
    }
}

3.双向循环链表的删除

逻辑上与双向链表的删除相同,所以可以借鉴

Status LinkListDelete(LinkList *L,int index,ElemType *e){
    int i=1;
    if(*L == NULL){
        return ERROR;
    }
    LinkList temp = (*L) ->next;
    if(temp->next == *L){//如果只剩下一个结点
        free(*L);
        *L == NULL;
        return OK;
    }
    while(i < index){
        temp = temp->next;
        i++;
    }
    *e = temp->data;
    temp ->prior ->next = temp->next;
    temp->next->prior = temp->prior;
    free(temp);
    return OK;
}

4.双向循环链表的查找

5.双向循环链表的替换

其他 上一节课的引申

  • 如何判断链表是否有环