单链表创建之--头插法创建带头结点的单链表,超详细

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单链表创建之--头插法创建带头结点的单链表,超详细相关的知识,希望对你有一定的参考价值。

参考技术A

单链表常见的创建方法有 头插法 尾插法 ,这里记录头插法创建 带头结点的单链表 具体过程:
以C语言为例,
1)首先使用 typedef 关键字定义结点数据类型

4行的 LNode 和 * LinkList 可有可无,有的话后面定义结点变量和指针变量时更方便,不必须在LNode前面加 struct 关键字,可直接这样定义变量,

与上面 typedef 关键字定义的单链表数据类型一样的定义方法:

若用这种方法定义链表结点类型,定义结点变量和指针变量时 必须 在LNode前带上 struct 关键字,即:

这两种定义方法效果是一样的,都是定义了包含 1个整型变量的数据域 1个后继指针域 的单链表结点类型

2)通过函数 头插构建链表,并返回 LinkList 类型表头指针变量 L
算法基本思想:带有头结点的单链表有两类结点, 头结点 元素结点 ,头结点通常不存储数据,用 L 表示,元素结点存储数据,用 s 表示

2.1 定义头结点指针变量 L 和元素结点 s

2.2 定义了头结点之后,内存中尚未分配空间,此时头结点并不真实存在,需使用 malloc 关键字分配存储空间后,并使 L 指针指之,才真正创建了 L 头结点。由于此时仅有头结点,无后继结点,需将其指针域置空

这时设置一个整型变量 x ,通过不断输入其值,来初始化各结点数据域 val ,判断 x =9999时为输入结束条件,先任意输入一个 x ,然后通过 while 循环来判断 x值决定是否进入添加结点过程

添加结点过程算法如下:
1, 初始化一个 s 元素结点,先初始化数据域 var ,然后初始化指针域 next

先初始化数据域 var ,然后初始化指针域 next 头插法是这样插入新结点的,新的结点 s 始终在当前的表中第一个元素结点之前
,也就是 L->next 之前插入,数据输入顺序与最终链表结点顺序是相反的,
所以在创建了一个新的元素结点 s 后,需要将其指针域置为 L->next , 如图

4,若输入的值非9999,则再次进入 while 循环,反复执行上述流程,不断插入元素结点扩大单链表长,这里赘述再添加一个元素结点的过程
又初始化了一个元素结点 s ,状态如图:

按照上述算法,头插法 新的元素结点 s 插入时始终插入在当前表中首个元素结点 F 之前,故需要将其后继指针域置为当前表中首个元素结点 F ,即 s->next = L->next , 记住 L->next 始终指向首个元素结点,结果如图:

元素结点 s 被“半插入”到表中后, F 已经不是绝对意义上的首个元素结点了,此时需要更改头结点 L 的后继指针域,将其后继指针域置为被“半插入”表中的新元素结点 s ,这样,新的元素结点 s 正式被插入表中,表长+1,如图

2.3 上述插入过程的函数完整实现:

4)主函数 main() 流程
需要初始化一个 head 指针变量,来接收 head_Insert() 函数所返回的已创建的链表头结点指针值, 然后将 head 传入 printList() 函数直接调用打印输入单链表数据,由于printList()是从首个结点开始打印,而头结点不存储数据,故传入第一个元素结点

程序最终运行结果如图,可以看到,头插法建立的单链表数据顺序与输入顺序相反:

C实现头插法和尾插法来构建单链表(不带头结点)

       链表的构建事实上也就是不断插入节点的过程。而节点的插入能够分为头插法和尾插法。

头插法就是在头结点后插入该节点,始终把该节点作为第一个节点。尾插法就是在链表的最后一个节点处插入元素,作为最后一个节点。假设想要了解链表的概念和其它链表操作。请參考《数据结构与算法之链表》《C语言实现链表的基本操作》两篇文章。演示样例代码上传至  https://github.com/chenyufeng1991/HeadInsertAndTailInsert

//
//  main.c
//  HeadInsertAndTailInsert
//
//  Created by chenyufeng on 16/2/25.
//  Copyright © 2016年 chenyufengweb. All rights reserved.
//

/**
 *  分别使用头插法和尾插法建立单链表
 */

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

typedef int elemType;
//构造节点
typedef struct ListNode{
    int element;
    struct ListNode *next;
}Node;

//初始化链表
void initList(Node *pNode){

    pNode = NULL;
    printf("%s函数运行,头结点初始化完毕\n",__FUNCTION__);
}

//打印链表
void printList(Node *pNode){
    if (pNode == NULL) {
        printf("%s函数运行,链表为空,打印失败\n",__FUNCTION__);
    }else{
        while (pNode != NULL) {
            printf("%d ",pNode->element);
            pNode = pNode->next;
        }
        printf("\n");
    }
}

//头插法
Node *HeadInsert(Node *pNode){

    Node *pInsert;
    pInsert = (Node*)malloc(sizeof(Node));
    if (pInsert == NULL) {
        printf("%s函数运行。内存分配失败,建立链表失败\n",__FUNCTION__);
        return NULL;
    }

    memset(pInsert, 0, sizeof(Node));
    scanf("%d",&(pInsert->element));
    pInsert->next = NULL;

    if (pInsert->element <= 0) {
        printf("%s函数运行。输入数据有误,建立链表失败\n",__FUNCTION__);
        return NULL;
    }

    while (pInsert->element > 0) {

        if (pNode == NULL) {
            pNode = pInsert;
        }else{
            //注意以下语句的顺序,否则可能造成链断裂
            pInsert->next = pNode;
            pNode = pInsert;
        }

        pInsert = (Node*)malloc(sizeof(Node));
        if (pInsert == NULL) {
            printf("%s函数运行,内存分配失败,建立链表失败\n",__FUNCTION__);
            return NULL;
        }

        memset(pInsert, 0, sizeof(Node));
        scanf("%d",&(pInsert->element));
        pInsert->next = NULL;
    }

    printf("%s函数运行。头插法建立链表成功\n",__FUNCTION__);

    return pNode;
}

//尾插法
Node *TailInsert(Node *pNode){

    Node *pInsert; //要插入的节点
    Node *pMove; //遍历链表的节点
    pInsert = (Node*)malloc(sizeof(Node));
    if (pInsert == NULL) {
        printf("%s函数运行,内存分配失败,建立链表失败\n",__FUNCTION__);
        return NULL;
    }

    memset(pInsert, 0, sizeof(Node));
    scanf("%d",&(pInsert->element));
    pInsert->next = NULL;

    if (pInsert->element <= 0) {
        printf("%s函数运行。输入数据有误,建立链表失败\n",__FUNCTION__);
        return NULL;
    }

    pMove = pNode;
    while (pInsert->element > 0) {
        if (pNode == NULL) {
            //注意不要忘了改动pMove指针的指向,初始pMove一定要指向头节点
            pNode = pInsert;
            pMove = pNode;
        }else{
            //遍历找到最后一个节点
            while (pMove->next != NULL) {
                pMove = pMove->next;
            }
            pMove->next = pInsert;
        }

        pInsert = (Node*)malloc(sizeof(Node));
        if (pInsert == NULL) {
            printf("%s函数运行。内存分配失败,建立链表失败\n",__FUNCTION__);
            return NULL;
        }

        memset(pInsert, 0, sizeof(Node));
        scanf("%d",&(pInsert->element));
        pInsert->next = NULL;
    }

    printf("%s函数运行,尾插法建立链表成功\n",__FUNCTION__);

    return pNode;
}

int main(int argc, const char * argv[]) {

    Node *pList;

    initList(pList);
    printList(pList);

    //头插法建立链表
    pList = HeadInsert(pList);
    printList(pList);

    //尾插法建立链表
    pList = TailInsert(pList);
    printList(pList);

    return 0;
}



以上是关于单链表创建之--头插法创建带头结点的单链表,超详细的主要内容,如果未能解决你的问题,请参考以下文章

每天进步一点点之带头节点单链表

C实现头插法和尾插法来构建非循环双链表(不带头结点)

单链表的创建

博客第二天——头插法建立单链表

单链表的创建插入删除遍历的Go实现

单链表的创建插入删除遍历的Go实现