C语言实现单链表(带头结点)的基本操作

我在之前一篇博客《C语言实现单链表(不带头结点)的基本操作》中具体实现了不带头结点的单链表的11种操作:如计算链表长度、初始化、创建链表、清空链表等等。但是在实际使用中,带头结点的单链表往往比不带头结点的单链表用的更多,使用也更为方便。因为不用单独考虑第一个节点的情况了,第一个节点和其他后续节点的处理全都一样了,简化操作。这篇博客将会来实现带头结点的单链表的11种操作。代码上传至: https://github.com/chenyufeng1991/LinkedList_HeadNode  。

(1)定义带头结点单链表的节点类型

typedef int elemType;
typedef struct NodeList{

    int element;
    struct NodeList *next;
}Node;

(2)初始化带头结点的单链表【这个很关键】

//1.初始化带头结点的单链表
void InitialList(Node **pNode){

    //个人建议每一次malloc分配内存空间后,都要进行判断分配是否成功,也即判断是否为空;
    //此时的这个pNode就是一个头结点;
    //初始化成功后,其实相当于是一个正常的链表了;
    *pNode = (Node *)malloc(sizeof(Node));
    if (*pNode == NULL) {
        printf("%s函数执行,内存分配失败,初始化单链表失败",__FUNCTION__);
    }else{

        (*pNode)->next = NULL;
        printf("%s函数执行,带头结点的单链表初始化完成\n",__FUNCTION__);
    }
}

(3)尾插法创建带头结点的单链表

//2.创建带头结点的单链表
void CreateList(Node *pNode){

    /**
     *  就算一开始输入的数字小于等于0,带头结点的单链表都是会创建成功的,只是这个单链表为空而已,也就是里面除了头结点就没有其他节点了。
     */
    Node *pInsert;
    Node *pMove;
    pInsert = (Node *)malloc(sizeof(Node));//需要检测分配内存是否成功 pInsert == NULL  ?
    memset(pInsert, 0, sizeof(Node));
    pInsert->next = NULL;

    scanf("%d",&(pInsert->element));
    pMove = pNode;
    while (pInsert->element > 0) {

        pMove->next = pInsert;
        pMove = pInsert;

        pInsert = (Node *)malloc(sizeof(Node)); //需要检测分配内存是否成功 pInsert == NULL  ?
        memset(pInsert, 0, sizeof(Node));
        pInsert->next = NULL;

        scanf("%d",&(pInsert->element));
    }

    printf("%s函数执行,带头结点的单链表创建成功\n",__FUNCTION__);
}

(4)打印带头结点的单链表

//3.打印带头结点的单链表
void PrintList(Node *pNode){
    /**
     *  注意这里,如果单链表为空(只有一个头结点),我也让它打印(打印成功)。只是里面没有元素,打出来是空的而已,所以在控制台上就是一行空的;
     */
        Node *pMove;
        pMove = pNode->next;
        while (pMove != NULL) {
            printf("%d ",pMove->element);
            pMove = pMove->next;
        }

        printf("\n%s函数执行,打印带头结点的单链表成功\n",__FUNCTION__);
}

(5)清空链表

//4.清除线性表中的所有元素,即释放所有节点(除了头结点),使之成为一个空表
void ClearList(Node *pNode){

    Node *pMove;
    pMove = pNode->next;
    while (pMove != NULL) {

        pNode->next = pMove->next;
        free(pMove);
        pMove = pNode->next;
    }

    printf("%s函数执行,清空带头结点的链表成功\n",__FUNCTION__);
}

(6)计算链表长度

//5.返回带头结点的单链表的长度
int SizeList(Node *pNode){
    /**
     *  当只有一个头结点的时候,size = 0;头节点不计算到链表长度中。
     */
    int i = 0;
    Node *pMove;
    pMove = pNode->next;
    while (pMove != NULL) {
        i++;
        pMove = pMove->next;
    }

    printf("%s函数执行,带头结点的单链表的长度为:%d\n",__FUNCTION__,i);

    return i;
}

(7)判断链表是否为空

//6.判断带头结点的单链表是否为空,为空则返回1,否则返回0
int IsEmptyList(Node *pNode){
    /**
     *  当只有一个头结点的时候,该链表就为空
     */
    if (pNode->next == NULL) {
        printf("%s函数执行,带头结点的链表为空\n",__FUNCTION__);
        return 1;
    }

    printf("%s函数执行,带头结点的链表非空\n",__FUNCTION__);

    return 0;
}

(8)查找链表某个位置元素

//7.返回单链表中第pos个结点中的元素,若返回-1,表示没有找到
int GetElement(Node *pNode,int pos){

    int i = 1;

    Node *pMove;
    pMove = pNode->next;

    while (pMove != NULL) {
        if (i == pos) {

            printf("%s函数执行,pos=%d位置的值是%d\n",__FUNCTION__,pos,pMove->element);
            return pMove->element;
        }

        i++;
        pMove = pMove->next;
    }

    printf("%s函数执行,在pos=%d位置没有找到值\n",__FUNCTION__,pos);
    return -1;
}

(9)返回某元素在链表中的内存地址

//8.从单链表中查找具有给定值x的第一个元素,若查找成功则返回该结点data域的存储地址,否则返回NULL
elemType* GetElemAddr(Node *pNode,int x){

    Node *pMove;
    pMove = pNode->next;

    while (pMove != NULL) {
        if (pMove->element == x) {
            printf("%s函数执行,查找到x=%d的内存地址为:0x%x\n",__FUNCTION__,x,&(pMove->element));
            return &(pMove->element);
        }
        pMove = pMove->next;
    }

    printf("%s函数执行,在带头结点的单链表中没有找到x=%d的值,无法获得内存地址\n",__FUNCTION__,x);

    return NULL;
}

(10)修改某个节点的值

//9.把单链表中第pos个结点的值修改为x的值
Node* ModifyElem(Node *pNode,int pos,int x){

    int i = 1;
    Node *pMove;
    pMove = pNode->next;
    while (pMove != NULL) {
        if (i == pos) {
            pMove->element = x;
            printf("%s函数执行,把pos=%d位置的值改为%d成功\n",__FUNCTION__,pos,x);
            return pNode;
        }
        i++;
        pMove = pMove->next;
    }
    printf("%s函数执行,链表为空或者输入pos值非法,修改值失败\n",__FUNCTION__);

    return pNode;
}

(11)表头插入一个节点

//10.向单链表的表头插入一个元素
Node *InsertHeadList(Node *pNode,int x){

    Node *pInsert;
    pInsert = (Node *)malloc(sizeof(Node));
    memset(pInsert, 0, sizeof(Node));
    pInsert->element = x;

    pInsert->next = pNode->next;
    pNode->next = pInsert;

    printf("%s函数执行,在表头插入元素%d成功\n",__FUNCTION__,x);
    return pNode;
}

(12)表尾插入一个节点

// 11.向单链表的末尾添加一个元素
Node *InsertTailList(Node *pNode,int x){

    Node *pMove;
    Node *pInsert;
    pInsert = (Node *)malloc(sizeof(Node));
    memset(pInsert, 0, sizeof(Node));
    pInsert->element = x;
    pInsert->next = NULL;

    pMove = pNode;
    while (pMove->next != NULL) {
        pMove = pMove->next;
    }
    pMove->next = pInsert;

    printf("%s函数执行,在表尾插入元素%d成功\n",__FUNCTION__,x);

    return pNode;
}

(13)测试函数

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

    Node *pList;

    InitialList(&pList);

    CreateList(pList);
    PrintList(pList);

    SizeList(pList);

    IsEmptyList(pList);

    GetElement(pList, 3);

    GetElemAddr(pList, 5);

    ModifyElem(pList, 2, 111);
    PrintList(pList);

    InsertHeadList(pList,1234);
    PrintList(pList);
    SizeList(pList);

    InsertTailList(pList,9999);
    PrintList(pList);
    SizeList(pList);

    ClearList(pList);
    PrintList(pList);

    return 0;
}
时间: 2024-12-15 06:53:54

C语言实现单链表(带头结点)的基本操作的相关文章

C语言实现单链表节点的删除(带头结点)

我在之前一篇博客<C语言实现单链表节点的删除(不带头结点)>中具体实现了怎样在一个不带头结点的单链表的删除一个节点,在这一篇博客中我改成了带头结点的单链表.代码演示样例上传至 https://github.com/chenyufeng1991/DeleteLinkedList_HeadNode.删除类型有两种: (1)删除某个位置pos的节点: (2)推断x值是否在链表中,若存在则删除该节点: 核心代码例如以下: //删除某个位置pos的节点 Node *DeletePosNode(Node

C语言实现单链表的节点插入(带头结点)

我在之前一篇博客<C语言实现单链表(不带头结点)节点的插入>中具体实现了怎样在一个不带头结点的单链表中进行节点的插入.可是在实际应用中,带头结点的链表更为经常使用.更为方便.今天我们就要来使用带头结点的单链表进行节点的插入.演示样例代码上传至 https://github.com/chenyufeng1991/InsertList_HeadNode  . 核心代码例如以下: Node *InsertNode(Node *pNode,int pos,int x){ int i = 0; Node

单链表的结点类模板

C++语言程序设计进阶 (2015年秋) 郑莉教授 http://www.xuetangx.com/courses?org=-1&cid=117&page_type=0&page=2 单链表 //单链表的结点类模板 template <class T> class Node{ private: Node<T> *next;//后继结点的指针 public: T data; Node(const T& item,Node<T>*next =

删除单链表某个结点(Java版)

题目:删除带头结点的单链表L中的结点p,p不是最后一个结点,要求时间复杂度为O(1). 解题思路: 如果不要求时间复杂度为O(1),我们可以找出p的前驱结点,然后很容易就删除p. 现在要求时间复杂度为O(1),因为p不是最后一个结点,知道结点p我们可以删除p的后继结点,那么我们可以把p的后继结点元素的值赋给p结点元素的值. ADT定义: //单链表的结点类 class LNode{ //为了简化访问单链表,结点中的数据项的访问权限都设为public public int data; public

单链表的插入伪算法和用C语言创建单链表,并遍历

非循环单链表插入结点伪算法讲解 q插入p之后的伪算法:第一种表示方法:r = p->pNext; // p->pNext表示的是所指向结点的指针域,指针域又是指向下一个结点的地址p->pNext = q; // q保存了那一块结点的地址.q是一个指针变量,存放那个结点的地址.q->pNext = r; 第二种表示方法:q->pNext = p->pNext; // q的指针域指向p后面一个结点p->pNext = q; // p的指针域指向q 删除非循环单链表结点

【LeetCode-面试算法经典-Java实现】【024-Swap Nodes in Pairs(成对交换单链表的结点)】

[024-Swap Nodes in Pairs(成对交换单链表的结点)] [LeetCode-面试算法经典-Java实现][所有题目目录索引] 原题 Given a linked list, swap every two adjacent nodes and return its head. For example, Given 1->2->3->4, you should return the list as 2->1->4->3. Your algorithm s

如何在O(1)的时间里删除单链表的结点

题目是这样的:给你一个单链表的表头,再给你其中某个结点的指针,要你删除这个结点,条件是你的程序必须在O(1)的时间内完成删除. 由于有的同学对链表还不是很熟悉,本文尽量描述的通俗易懂,老鸟请直接跳过前面一大段. 链表结构如下: [cpp] view plaincopyprint? struct node { int val; node* next; }; 题目不是很难,很快就能想到好办法:) 首先回顾一下普通的删除方法,首先通过表头,找到待删除结点(设为B)的前一个结点(设为A),将A的指向改一

[算法浅析] 如何在O(1)的时间里删除单链表的结点

题目是这样的:给你一个单链表的表头,再给你其中某个结点的指针,要你删除这个结点,条件是你的程序必须在O(1)的时间内完成删除. 由于有的同学对链表还不是很熟悉,本文尽量描述的通俗易懂,老鸟请直接跳过前面一大段. 链表结构如下: struct node { int val; node* next; }; 题目不是很难,很快就能想到好办法:) 首先回顾一下普通的删除方法,首先通过表头,找到待删除结点(设为B)的前一个结点(设为A),将A的指向改一下就行,然后删除掉B结点就行了.要删除的结点一定要de

求两个单链表公共结点

题目:输入两个单链表,找出公共结点. 思路:若两个单链表有公共结点,其形状必定为"Y"型,也就是说公共结点后的所有结点都是相同的. 我们首先获得两个链表的长度,求得长度之差为n,再定义两个指针分别指向两个链表首部,长链表先走n步,然后两个指针同时走,直到两个指针所指向的值完全相同时停止. 代码: /* 求链表公共结点 */ #include<stdio.h> #include<stdlib.h> typedef struct _NODE_ { int data;