数据结构-链表链表的基本操作

Posted Mount256

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构-链表链表的基本操作相关的知识,希望对你有一定的参考价值。

文章目录


编写插入函数和删除函数的思路:

  • 先考虑一般情况;
  • 再考虑在链表头部的操作;
  • 最后考虑在链表尾部的操作。

1 单向链表

1.1 有头结点的单向链表

1.1.1 数据结构定义

typedef struct LinkNode
    int data;
    LinkNode *next;
 *LinkNode, LinkList;

1.1.2 初始化建立链表

  • 头插法:
LinkList InitList (LinkList &L)
    LinkNode *newNode, *head;
    int x;

    // 建立头结点
    head = (LinkList) malloc(sizeof(LinkList));
    head->next = NULL;
    L = head;
    
    while (不符合终止条件)
        x = 读入数据;
        newNode = (LinkNode *) malloc(sizeof(LinkNode));
        newNode->data = x;
        newNode->next = head->next; // 新结点的指针域指向头结点的后继结点
        head->next = newNode; // 头结点的指针域指向新结点
    
    
    return L;

  • 尾插法:
LinkList InitList (LinkList &L)
    LinkNode *newNode, *head, *tail;
    int x;

    // 建立头结点
    head = (LinkList) malloc(sizeof(LinkList));
    head->next = NULL;
    tail = head;
    L = head;
    
    while (不符合终止条件)
        x = 读入数据;
        newNode = (LinkNode *) malloc(sizeof(LinkNode));
        newNode->data = x;
        newNode->next = NULL;
        tail->next = newNode; // 原先尾结点的指针域指向新结点
        tail = newNode; // 尾指针指向新结点
    
    
    return L;

1.1.3 按序号查找结点

LinkNode *GetNumNode (LinkList &L, int pos)
    LinkNode *findNode = L; // 初始指向头结点
    
    if (pos == 0) // 第 0 个结点即头结点
        return L;
    else if (pos < 0) // 必须为非负值
        return NULL;
    
    while ((findNode != NULL) && (pos != 0))
        findNode = findNode->next;
        pos--;
    
    return findNode;

1.1.4 按值查找结点

LinkNode *GetDataNode (LinkList &L, const int x)
    LinkNode *findNode = L;
    
    while ((findNode != NULL) && (findNode->data != x))
        findNode = findNode->next;

    return findNode;

1.1.5 插入操作

  • 新结点插入到第 pos 个位置上(找到其前驱结点即第 pos-1 个结点,进行后插操作):
bool InsertNode (LinkList &L, int pos, const int x)
    LinkNode *newNode; // 新结点
    LinkNode *posPrev; // 记录第 pos-1 个结点
    LinkNode *posNode; // 记录第 pos 个结点
    
    if (pos <= 0) // 不能插在头结点的位置上
        return false;
    
    posPrev = GetNumNode(L, pos-1); // 先找到第 pos-1 个结点
    if (posPrev == NULL)
        return false;
    posNode = posPrev->next;
    
    newNode = (LinkNode *) malloc(sizeof(LinkNode));
    newNode->data = x;
    newNode->next = posNode; // 新结点的指针域指向原先第 pos 个结点
    posPrev->next = newNode; // 第 pos-1 个结点的指针域指向新结点
    
    return true;

  • 新结点插入到第 pos 个位置上(找到该结点即第 pos 个结点,进行伪前插操作,实质是新结点插入到第 pos 个结点的后面,然后交换数据域):
bool InsertNode (LinkList &L, int pos, const int x)
    LinkNode *newNode; // 新结点
    LinkNode *posNode; // 记录第 pos 个结点
    LinkNode *posNext; // 记录第 pos+1 个结点
    
    if (pos <= 0) // 不能插在头结点的位置上
        return false;
    
    posNode = GetNumNode(L, pos); // 先找到第 pos 个结点
    if (posNode == NULL)
        return false;
    posNext = posNode->next; // 记录第 pos+1 个结点
    
    newNode = (LinkNode *) malloc(sizeof(LinkNode));
    newNode->data = posNode->data; // 交换数据,posNode 变为新结点,newNode 变为旧结点
    newNode->next = posNext; 
    posNode->data = x;
    posNode->next = newNode; 
    
    return true;

1.1.6 删除操作

  • 删除第 pos 个结点(找到其前驱结点即第 pos-1 个结点):
bool DeleteNode (LinkList &L, int pos)
    LinkNode *posPrev; // 记录第 pos-1 个结点
    LinkNode *posNode; // 记录第 pos 个结点
    LinkNode *posNext; // 记录第 pos+1 个结点
    
    if (pos <= 0) // 不能删除头结点
        return false;
    
    posPrev = GetNumNode(L, pos-1); // 先找到第 pos-1 个结点
    if (posPrev == NULL)
        return false;
    posNode = posPrev->next; // 记录第 pos 个结点
    posNext = posNode->next; // 记录第 pos+1 个结点
    
    posPrev->next = posNext; // 第 pos-1 个结点的指针域指向原先第 pos 个结点的后继结点(即原先第 pos+1 个结点)
    free(posNode);
    
    return true;

  • 删除第 pos 个结点(找到该结点即第 pos 个结点,将其后继结点的值赋值给第 pos 个结点,然后删除其后继结点):
bool DeleteNode (LinkList &L, int pos)
    LinkNode *posNext; // 记录第 pos+1 个结点
    LinkNode *posNode; // 记录第 pos 个结点
    
    if (pos <= 0) // 不能删除头结点
        return false;
    
    posNode = GetNode(L, pos); // 先找到第 pos 个结点
    if (posNode == NULL)
        return false;
    posNext = posNode->next; // 记录第 pos+1 个结点
    
    if (posNext != NULL) // 如果第 pos 个结点不是最后一个结点
        posNode->data = posNext->data; // 将其后继结点的值赋值给第 pos 个结点
        posNode->next = posNext->next; // 更新指针域
        free(posNext);
    
    else // 如果第 pos 个结点是最后一个结点
        free(posNode);
        前驱结点的指针域 = NULL; // 这里还是需要再遍历一遍链表找到前驱结点,比较麻烦
    
    
    return true;

1.2 无头结点的单向链表

1.2.1 数据结构定义

typedef struct LinkNode
    int data;
    LinkNode *next;
 *LinkNode, LinkList;

1.2.2 初始化建立链表

  • 头插法:
LinkList InitList (LinkList &L)
    LinkNode *newNode, *head;
    int x;

    // 建立第一个结点
    x = 读入数据;
    head = (LinkList) malloc(sizeof(LinkList));
    head->data = x;
    head->next = NULL;
    L = head;
    
    while (不符合终止条件)
        x = 读入数据;
        newNode = (LinkNode *) malloc(sizeof(LinkNode));
        newNode->data = x;
        newNode->next = head;
        head = newNode; // 头指针指向新结点
        L = head; // 更新头指针(即链表的入口)
    
    
    return L;

  • 尾插法:
LinkList InitList (LinkList &L)
    LinkNode *newNode, *head, *tail;
    int x;

    // 建立第一个结点
    x = 读入数据;
    head = (LinkList) malloc(sizeof(LinkList));
    head->data = x;
    head->next = NULL;
    tail = head;
    L = head;
    
    while (不符合终止条件)
        x = 读入数据;
        newNode = (LinkNode *) malloc(sizeof(LinkNode));
        newNode->data = x;
        newNode->next = NULL;
        tail->next = newNode; // 原先尾结点的指针域指向新结点
        tail = newNode; // 尾指针指向新结点
    
    
    return L;

1.2.3 按序号查找结点

LinkNode *GetNumNode (LinkList &L, int pos)
    LinkNode *findNode = L; // 初始时指向链表头部
    
    if (pos < 1) // 必须为非负值
        return NULL;
    
    while ((findNode != NULL) && (pos != 0))
        findNode = findNode->next;
        pos--;
    
    return findNode;

1.2.4 按值查找结点

LinkNode *GetDataNode (LinkList &L, const int x)
    LinkNode *findNode = L; // 初始时指向链表头部
    
    while ((findNode != NULL) && (findNode->data != x))
        findNode = findNode->next;

    return findNode;

1.2.5 插入操作

  • 新结点插入到第 pos 个位置上(找到其前驱结点即第 pos-1 个结点,进行后插操作):
bool InsertNode (LinkList &L, int pos, const int x)
    LinkNode *newNode; // 新结点
    LinkNode *posPrev; // 记录第 pos-1 个结点
    LinkNode *posNode; // 记录第 pos 个结点
    
    if (pos <= 0) // 不能插在头结点的位置上
        return false;
    
    if (pos == 1) // 如果要插入到第 1 个位置
        newNode = (LinkNode *) malloc(sizeof(LinkNode));
        newNode->data = x;
        newNode->next = L; // 指针域指向头结点
        L = newNode; // 更新头指针(即链表的入口)
    
    else
        posPrev = GetNumNode(L, pos-1); // 先找到第 pos-1 个结点
        if (posPrev == NULL)
            return false;
        posNode = posPrev->next; // 记录第 pos 个结点
        newNode = (LinkNode *) malloc(sizeof(LinkNode));
        newNode->data = x;
        newNode->next = posNode; // 新结点的指针域指向原先第 pos 个结点
        posPrev->next = newNode; // 第 pos-1 个结点的指针域指向新结点
    
    
    return true;

  • 新结点插入到第 pos 个位置上(找到该结点即第 pos 个结点,进行伪前插操作,实质是新结点插入到第 pos 个结点的后面,然后交换数据域):
bool InsertNode (LinkList &L, int pos, const int x)
    LinkNode *newNode; // 新结点
    LinkNode *posNode; // 记录第 pos 个结点
    LinkNode *posNext; // 记录第 pos+1 个结点
    
    if (pos <= 0) // 不能插在头结点的位置上
        return false;
    
    posNode = GetNumNode(L, pos); // 先找到第 pos 个结点
    if (posNode == NULL)
        return false;
    posNext = posNode->next;
    
    newNode = (LinkNode *) malloc(sizeof(LinkNode));
    newNode->data = posNode->data; // 交换数据,posNode 变为新结点,newNode 变为旧结点
    newNode->next = posNext; 
    posNode->data = x;
    posNode->next = newNode; 
    
    return true;

1.2.6 删除操作

  • 删除第 pos 个结点(找到其前驱结点即第 pos-1 个结点):
bool DeleteNode (LinkList &L, int pos)
    LinkNode *posPrev; // 记录第 pos-1 个结点
    LinkNode *posNode; // 记录第 pos 个结点
    LinkNode *posNext; // 记录第 pos+1 个结点
    
    if (pos <= 0)
        return false;
    
    if (pos == 1) // 如果要删除第 1 个结点
        posNext = L->next; // 记录第 2 个结点
        free(L);
        L = posNext; // 头指针指向第 2 个结点
    
    else
        posPrev = GetNumNode(L, pos-1); // 先找到第 pos-1 个结点
        if (posPrev == NULL)
            return false;
        posNode = posPrev->next; // 记录第 pos 个结点
        posNext =  posNode->next; // 记录第 pos+1 个结点
        posPrev->next = posNext; // 第 pos-1 个结点的指针域指向原先第 pos 个结点的后继结点(即原先第 pos+1 个结点)
        free(posNode);
    
    
    return true;

  • 删除第 pos 个结点(找到该结点即第 pos 个结点,将其后继结点的值赋值给第 pos 个结点,然后删除其后继结点):
bool DeleteNode (LinkList &L, int pos)
    LinkNode *posNext; // 记录第 pos+1 个结点
    LinkNode *posNode; // 记录第 pos 个结点
    
    if (pos <= 0)
        return false;
    
    posNode = GetNumNode(L, pos); // 先找到第 pos 个结点
    if (posNode == NULL)
        return false;
    posNext = posNode->next; // 记录第 pos+1 个结点
    
    if (posNext != NULL) // 如果第 pos 个结点不是最后一个结点
        posNode->data = posNext->data; // 将其后继结点的值赋值给第 pos 个结点
        posNode->next = posNext->next; // 更新指针域
        free(posNext);
    
    else // 如果第 pos 个结点是最后一个结点
        free(posNode);
        前驱结点的指针域 = NULL; // 这里还是需要再遍历一遍链表找到前驱结点,比较麻烦
    
    
    return true;

2 双向链表

2.1 有头结点的双向链表

2.1.1 数据结构定义

typedef struct LinkNode
    int data;
    LinkNode *prev;
    LinkNode *next;
 *LinkNode, LinkList;

2.1.2 初始化建立链表

  • 头插法:
LinkList InitList (LinkList &L)
    LinkNode *newNode, *head;
    int x;

    // 建立头结点
    head = (LinkList) malloc(sizeof(LinkList));
    head->prev = NULL;
    head->next = NULL;
    L = head;
    
    while (不符合终止条件)
        x = 读入数据;
        newNode = (LinkNode *) malloc(sizeof(LinkNode));
        newNode->data = x;
        newNode->prev = head;
        newNode->next = head->next; // 新结点的指针域指向头结点的后继结点
        head->next = newNode; // 头结点的指针域指向新结点
    
    
    return L;

  • 尾插法:
LinkList InitList (LinkList &L)
    LinkNode *newNode, *head, *tail;
    int x;

    // 建立头结点
    head = (LinkList) malloc(sizeof(LinkList));
    head->prev = NULL;
    head->next = NULL;
    tail = head;
    L = head;
    
    while (不符合终止条件)
        x = 读入数据;
        newNode = (LinkNode *) malloc(sizeof(LinkNode));
        newNode->data = x;
        newNode->prev = tail;
        newNode->next = NULL;
        tail->next = newNode; // 原先尾结点的指针域指向新结点
        tail = newNode; // 尾指针指向新结点
    
    
    return L;

2.1.3 按序号查找结点

LinkNode *GetNumNode (LinkList &L, int pos)
    LinkNode *findNode = L; // 初始指向头结点
    
    if (pos == 0) // 第 0 个结点即头结点
        return L;
    else if (pos < 0) // 必须为非负值
        return NULL;
    
    while ((findNode != NULL) && (pos != 0))以上是关于数据结构-链表链表的基本操作的主要内容,如果未能解决你的问题,请参考以下文章

链表

JavaScript单向链表的创建遍历插入删除操作

线性表之双向链表

2017/03/31学习笔记

数据结构-链表链表的相关算法

数据结构——双向链表的实现