单链表二[不带头节点链表]

不带头节点链表

单向链表是链表的一种。单向链表由一系列内存不连续的节点组成,每个节点都包含指向值的域和指向下个节点的next指针。最后一个节点的next域为NULL值,代表链表结束。

链表示意图如下:

一,结构体

1,结构体定义:

struct LinkNode
{
    void *x; 
    struct LinkNode *next;
};

2,结构体大小:

1)取结构体大小方法:sizeof(struct LinkNode);在64位系统取出结构体大小为:sizeof(struct LinkNode) = 16;

2)为什么是16字节:因为本结构体包含的两个指针成员x和next。指针是存放地址的,故在同一系统平台下,指针变量取的sizeof大小都是一致。即对于指针变量的大小并不取决于指针类型,而取决于系统平台。32位=4字节,64位=8字节。故有在64位系统中sizeof(void *) == sizeof(struct LinkNode *) == 8。在32位系统中,sizeof(void *) == sizeof(struct LinkNode *) == 4。

3)若假设节点ABCD是内存连续的且A作为内存其起始点,即A的地址为0x00,那么此时B,C,D的地址就依次为:0x10,0x20,0x30。且A的next指针指向的是节点B(A->next = &B),依次类推,直到节点D的next存的是结束符NULL。

二,链表创建

1,链表创建一(使用一级指针)

程序说明:

1)程序调用方式szyu_link_create1("AA", "BB", NULL),NULL用于正确终止for循环。

2)创建新增节点node。

3)如果链表为空,则先把新增节点(node)赋值给head,并让last指向最新的head;如果链表不为空,则把尾节点的next指向最新节点,并重新赋值尾节点即可。

struct LinkNode
*szyu_link_create1(void *x, ...)
{
    struct LinkNode *head = NULL;
    struct LinkNode *last = head;

    va_list args;
    va_start(args, x);

    for ( ; x ; x = va_arg(args, void *) )
    {
        struct LinkNode *node = NULL;
        node = (struct LinkNode *)malloc(sizeof(struct LinkNode));
        if ( node == NULL )
        {
            return head;
        }

        node->x = x;
        node->next = NULL;

        if ( head == NULL )
        {
            head = node;
            last = head;
        }
        else 
        {
            last->next = node;
            last = node;
        }
    }
    va_end(args);

    return head;
}

2,链表创建二(使用二级指针)

程序说明:

1)二级指针node存在如下成立等式:*node == head,**node = *head;

2)for刚开始为*node(*node  = head)创建空间,既创建头节点。

3)为(*node)节点的x赋值,并让指针node指向新节点的next,即赋值后*node即为前node的next域值。

4)第二次for开始,为*node赋值就是给(*node)->next赋值。

5)重复步骤3,4直到NULL传入为止。

6)最后一个节点把node指向next后并未对其进行赋NULL值处理。故在for循环结束要为*node赋值NULL。代表链表结束。

struct LinkNode
*szyu_link_create2(void *x, ...)
{
    struct LinkNode *head  = NULL;
    struct LinkNode **node = &head;

    va_list args;
    va_start(args, x); 

    for ( ; x; x = va_arg(args, void *) )
    {   
        (*node) = (struct LinkNode *)malloc(sizeof(struct LinkNode));
        if ( (*node) == NULL )
        {   
            return head;
        }   

        (*node)->x = x;

        node = &(*node)->next;
    }   
    *node = NULL;
    va_end(args);

    return head;
}

3,一级指针和二级指针对比

一级指针

1)优点:程序通俗易懂。

2)缺点:插入头节点和插入其他位置方式不同,代码风格不统一。

二级指针

1)优点:无论插入什么位置,代码风格高度统一。代码精简。

2)缺点:技巧性较高。

4,设计思路

二级指针的使用场景就是“间接改变一级指针所指向的内存地址”。而改变的一级指针指向的即为next指针。除头节点外的所有节点新增地址都存在上一节点的next中,固有设计node指向next,为*node赋值时即为next赋值。

三,链表插入

1,链表插入一(使用一级指针)

程序说明:

1)key的判断保证输入位置不能小于1,并可以在链表最后面插入新节点。

2)初始化新增节点。

3)int cnt = 2;在key = 1时,是要重新插入第一个节点;key = 2 时插入的前一个节点即为第一节点。所以在key <= 2时是不需要进行链表移动,故cnt = 2开始执行。

4)由于不带头节点,故在插入时,插入在头节点位置和后面位置需要区分考虑。

struct LinkNode
*szyu_link_insert1(struct LinkNode *head, void *x, int key)
{
    if ( head == NULL )
    {
        return head;
    }

    int len = szyu_link_length1(head);

    if ( key < 1 || key - 1 > len )
    {
        return head;
    }

    struct LinkNode *node = NULL;
    node = (struct LinkNode *)malloc(sizeof(struct LinkNode));
    if ( node == NULL )
    {
        return head;
    }

    node->x = x;
    node->next = NULL;

    struct LinkNode *list = head;
    
    int cnt = 2;
    for ( ; cnt < key; cnt++ )
    {
        list = list->next;
    }

    if ( key == 1 )
    {
        node->next = head;
        head = node;
    }
    else
    {
        node->next = list->next;
        list->next = node;
    }

    return head;
}

2,链表插入二(使用二级指针)

程序说明:

1)key - 1是保证在链表后面插入节点正常。

2)由于使用二级指针故cnt初始化为1即可,无须单独考虑插入头节点情况。

struct LinkNode                                                                           
*szyu_link_insert2(struct LinkNode *head, void *x, int key)
{
    if ( head == NULL )
    {
        return head;
    }

    int len = szyu_link_length1(head);

    if ( key < 1 || key - 1 > len )
    {
        return head;
    }

    struct LinkNode **list = &head;

    int cnt = 1;

    while ( cnt < key )
    {
        list = &(*list)->next;
        cnt += 1;
    }
    struct LinkNode *remain = *list;

    *list = (struct LinkNode *)malloc(sizeof(struct LinkNode));
    if ( (*list) == NULL )
    {
        return head;
    }

    (*list)->x = x;
    (*list)->next = remain;

    return head;
}

3,使用一级指针和二级指针优缺点同链表创建

4,使用二级指针设计思路

1)首先使二级指针list指向一级指针head。

2)循环使用链表停留在插入位置的前一节点上。此时若不是头节点位置,list指向的是插入位置前一节点的next,插入时,只需为*list赋值新节点地址即可。若是头节点,则*list指向头节点。

3)无论是否为头节点,把剩下链表赋值给remain(若插入为头节点,此时remain保留的事整个链表;若插入在最后,则remain为NULL)。

4)为*list赋值新节点地址。并把remain追加到*list节点后面即可。

四,链表节点删除

1,链表节点删除(一级指针)

程序说明:

1)如果头节点为要删除节点,只需要把head指向head->next即可。

2)由于delete停留在要删除节点的前一节点,故只需要把delete->next赋值给remain,在free即可。

struct LinkNode
*szyu_link_delete1(struct LinkNode *head, void *x)
{
    if ( head == NULL )
    {
        return NULL;
    }

    struct LinkNode *delete = head;
    struct LinkNode *remain = NULL;
    if ( strcmp((char *)delete->x, (char *)x) == 0 )
    {
        remain = delete;
        head = delete->next;
    }
    else
    {
        while ( delete->next != NULL && strcmp((char *)delete->next->x, (char *)x) != 0)
        {
            delete = delete->next;                                                  
        }

        remain = delete->next;
        delete->next = delete->next->next;
    }

    free(remain);

    return head;
}

2,链表节点删除(二级指针)

程序说明

1)若为头节点时,*list = head,head = head->next即可,即为*list = (*list)->next。

2)若不为头节点,list是指向next的指针,此时*list即为下个节点,若要删除下个节点,为*list重新赋值即可改变下个节点指向。

struct LinkNode
*szyu_link_delete2(struct LinkNode *head, void *x) 
{
    if ( head == NULL )
    {   
        return head;
    }   

    struct LinkNode **list = &head;
    while ( (*list) != NULL && strcmp((char *)(*list)->x, (char *)x) != 0 ) 
    {   
        list = &(*list)->next;
    }   

    struct LinkNode *remain = *list;

    (*list) = (*list)->next;

    free(remain);

    return head;
}

五,链表释放

程序说明:

1)使用二级指针后的*head即为删除节点。

void
szyu_link_free2(struct LinkNode **head)
{
    if ( *head == NULL || head == NULL )
    {
        return;
    }

    struct LinkNode *next = NULL;
    for ( ; *head; *head = next )
    {
        next = (*head)->next;
        free(*head);                                                                
    }
}

六,链表长度获取

程序说明:

1)由于链表不带头节点,故直接赋值head链表。

int
szyu_link_length1(struct LinkNode *head)
{
    if ( head == NULL )
    {
        return 0;
    }

    struct LinkNode *pLen = head;
    int len = 0;
    for ( ; pLen != NULL; pLen = pLen->next )
    {
        len += 1;
    }

    return len;
}

七,链表打印

void
szyu_link_print1(struct LinkNode *head)
{
    if ( head == NULL )
    {
        return;
    }

    struct LinkNode *print = head;
    for ( ; print != NULL; print = print->next )
    {
        printf("%s ", (char *)print->x);
    }

    printf("\n");
}
时间: 2024-12-06 04:19:44

单链表二[不带头节点链表]的相关文章

单链表一[带头节点链表]

单链表实现分带头节点链表和不带头节点链表: 使用头文件如下: struct LinkNode {     void *x;      struct LinkNode *next; }; 一,带头节点的链表: 1,链表创建 程序说明: 1)函数调用形式:szyu_link_create0("AA", "BB", NULL);其中NULL结尾是在for循环的判断结束条件为x == NULL.使用NULL可以是for循环正常退出 2)程序先创建头节点head,并初始化he

[华为机试练习题]24.删除链表中的反复节点、剩余节点逆序输出

题目 描写叙述: 题目描写叙述: 输入一个不带头节点的单向链表(链表的节点数小于100),删除链表中内容反复的节点(反复的节点所有删除),剩余的节点逆序倒排. 要求实现函数: void vChanProcess(strNode * pstrIn,strNode * pstrOut); [输入] pstrIn:输入一个不带头节点的单向链表 [输出] pstrOut:删除内容反复的节点(反复的节点所有删除).剩余节点逆序输出(不带头节点,链表第一个节点的内存已经申请). [注意]仅仅须要完毕该函数功

[华为机试练习题]24.删除链表中的重复节点、剩余节点逆序输出

题目 描述: 题目描述: 输入一个不带头节点的单向链表(链表的节点数小于100),删除链表中内容重复的节点(重复的节点全部删除),剩余的节点逆序倒排. 要求实现函数: void vChanProcess(strNode * pstrIn,strNode * pstrOut); [输入] pstrIn:输入一个不带头节点的单向链表 [输出] pstrOut:删除内容重复的节点(重复的节点全部删除),剩余节点逆序输出(不带头节点,链表第一个节点的内存已经申请). [注意]只需要完成该函数功能算法,中

删除链表中的重复节点、剩余节点逆序输出

#include <stdlib.h> #include <algorithm> #include <functional> #include <iostream> #include "oj.h" using namespace std; /* 功能: 输入一个不带头节点的单向链表(链表的节点数小于100),删除链表中内容重复的节点(重复的节点全部删除),剩余的节点逆序倒排. 输入: pstrIn: 输入一个不带头节点的单向链表 输出:

删除单向链表中的某个节点

删除单向链表中的某个节点 链表的节点删除 在删除链表的节点步骤如下: 1.找到被删除节点的前面一个节点 2.将前面节点的next节点改成下一个节点 3.将被删除节点的内存释放 public class deleteNode { Node head; class Node { int data; Node next; Node(int d) { data = d; next = null; } } void deleteNode(int key) { // Store head node Node

单链表——带头节点

一.链表简介 1 数据结构中,链表是最基础的.然而链表根据不同的需求分成的种类很多,单向或双向链表,循环或非循环链表,带头节点或者不带头节点的链表. 2 本文实现——带头节点的单链表. 3 由于仅仅是学习链表的基本操作,所以在数据字段仅仅设置一个字段:   由于仅仅是学习基本操作,不涉及复杂的算法思想,所以不会很难,主要以代码为主,附上必要的解释即可. 二.具体实现 整体分析:带有头节点的单链表的操作很方便,主要体现在插入和删除时不需要判断是否是第一个元素. 1) 头文件定义如下: 1 #ifn

带头节点的单链表的插入操作

1.偶然看到了十字链表的应用,想到之前在<数据结构与算法分析>的链表一章中,需要用多重表实现一个简单的查询功能.功能需求如下: “已知 学生 和 学校课程 总数 分别为 40000 和 2500,现在需要得到两份报告,一份显示每门课成注册的所有学生信息, 一份显示每个学生注册了哪些课程.” 显然可以用一个 40000 * 2500 个元素的二维数组来解决,但是每个学生选课数目很少,因此会浪费很多空间.因此选择十字链表来实现. 既然是链表,那么肯定要有插入操作,于是便有了本文.算是对功能实现前的

带头节点的单链表

//带头结点的单链表 #include <iostream> #include <stdlib.h> using namespace std; typedef int ElemType; typedef struct Node { ElemType data; struct Node *next; }LNode,*LinkList; void InitList(LinkList *L); void Create_head(LinkList l); void Create_rear(

带头节点的单链表-------C语言实现

1 /***************************************************** 2 Author:Simon_Kly Version:0.1 Date:20170520 3 Description:带头接点的单链表 4 Mail:[email protected] 5 Funcion List: 6 *****************************************************/ 7 8 #include <stdio.h> 9 #