单链表总结篇

【基本概念】单链表即单向链表,数据结构为一个接一个的结点组成,每个结点有两个成员,一个数据域一个指向下一个结点的指针,如下:

struct Node
{
    int data;
    struct Node *next;
};


单链表基本操作包括链表初始化、插入、删除,其中初始化操作是指让单链表存在一个头结点,其数据域随机,头结点指向下一个结点,每次访问都要从头结点开始访问,插入结点方式有两种,尾部插入和结点前部插入,尾部插入很简单与正常的输入顺序一致,而前部插入需要时常变动头结点的指针,始终让他指向新插入的,因为如果不调整头指针的话,在输出时是无法从头结点往前访问的,记住,它是单向链表。删除操作主要是定值查找删除,在链表里并不需要做什么删除操作,其实就是将前一结点指针指向目标节点的下一个结点位置,指针访问时直接跳跃,即可实现删除操作。



【测试代码】

#include<stdio.h>
#include<stdlib.h>
#include<stack>

typedef int data_type;

typedef struct Node node_t;// 给struct Node取个别名node_t
typedef struct Node * node_ptr;//给struct Node*取个别名node_ptr

typedef struct Node
{
    data_type data;
    struct Node *node_next;//node_next是一个指向结构的指针,告诉指针要指向的地址就要付给它一个结构类型地址
};

//链表初始化
node_t * init()
{
    node_ptr p;
    p = (node_t *)malloc(sizeof(node_t));
    p->node_next = NULL;
    return p;
}
//在链表后面插入结点
node_t *insert_back(node_ptr p , data_type data)
{

    node_ptr pnew = (node_t *)malloc(sizeof(node_t));
    pnew ->node_next = NULL;
    pnew ->data = data;

    p->node_next = pnew;

    return pnew;
}

void remove(node_ptr p, data_type data)
{
    node_ptr find = p;
    if(!find)
        return ;
    while(find->node_next->data !=data)
    {
        find= find->node_next;
    }
    find->node_next = find->node_next->node_next ;

}
//正常打印
void print(node_ptr p)
{
    if(!p)
    {
            printf("no data, you think too much");
            return ;
    }

    while(p->node_next != NULL)
    {
        printf("%d ", p->data);
        p = p->node_next;
    }
    printf("%d ", p->data);
    printf("\n");

}

void main()
{
    node_ptr pnode, list;
    pnode = init();
    list = pnode;

    pnode = insert_back(pnode, 1);
    pnode = insert_back(pnode, 2);
    pnode = insert_back(pnode, 3);
    pnode = insert_back(pnode, 4);
    pnode = insert_back(pnode, 5);
    pnode = insert_back(pnode, 6);

    printf("normal print:");
    print(list->node_next);
    printf("-------------------------------------------\n");
    remove(list,1);
    printf("remove one node 1 print:");
    print(list->node_next);
    printf("-------------------------------------------\n");
    remove(list,2);
    remove(list,3);
    remove(list,4);
    remove(list,5);
    remove(list,6);
    printf("remove all print:");
    print(list->node_next);
    printf("\n-------------------------------------------\n");

}

【输出】

这段测试代码中使用的是尾部插入,设置了一个指针pnode指向尾结点,指针list始终指向头结点,访问链表时从list开始,而pnode就用于插入新结点和删除结点,插入的新节点永远在尾部后面,这样要比**list形式理解起来简单一点,大部分的资料都喜欢用双重指针,但是双重指针繁杂不易理解,尤其在访问地址变换的时候,很容易出错,所以先以这种简单的方式来理解单链表的基本思想。

结点存储方式如下

以前部插入为例,设计测试代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<stack>

typedef int data_type;

typedef struct Node node_t;// 给struct Node取个别名node_t
typedef struct Node * node_ptr;//给struct Node*取个别名node_ptr

typedef struct Node
{
    data_type data;
    struct Node *node_next;//node_next是一个指向结构的指针,告诉指针要指向的地址就要付给它一个结构类型地址
};

node_t * init()
{
    node_ptr p;
    p = (node_t *)malloc(sizeof(node_t));
    p->node_next = NULL;
    return p;
}
//链表从前面插入
node_t * insert_front(node_ptr p , data_type data)
{
    p->data = data;
    node_ptr pnew = (node_t *)malloc(sizeof(node_t));
    pnew->node_next = p;

    return pnew;
}
void remove(node_ptr p, data_type data)
{
    node_ptr find = p;
    if(!find)
        return ;
    while(find->node_next->data !=data)
    {
        find= find->node_next;
    }
    find->node_next = find->node_next->node_next ;

}
//正常打印
void print(node_ptr p)
{
    if(!p)
    {
            printf("no data, you think too much");
            return ;
    }

    while(p->node_next != NULL)
    {
        printf("%d ", p->data);
        p = p->node_next;
    }
    printf("%d ", p->data);
    printf("\n");

}

void main()
{
    node_ptr pnode, list;
    pnode = init();

    pnode = insert_front(pnode, 1);
    pnode = insert_front(pnode, 2);
    pnode = insert_front(pnode, 3);
    pnode = insert_front(pnode, 4);
    pnode = insert_front(pnode, 5);
    pnode = insert_front(pnode, 6);
    list = pnode;

    printf("normal print:");
    print(list);
    printf("-------------------------------------------\n");
    remove(list,1);
    printf("remove one node 1 print:");
    print(list->node_next);
    printf("-------------------------------------------\n");
    remove(list,2);
    remove(list,3);
    remove(list,4);
    remove(list,5);
    remove(list,6);
    printf("remove all print:");
    print(list->node_next);
    printf("\n-------------------------------------------\n");

}

【输出】

注意两个测试代码输出有什么区别,前向插入,是倒着输出的,跟输入顺序不一样。

其他单链表相关操作都是在此基础上做的,忘记了单链表怎么操作时可以参考的

时间: 2024-08-08 17:51:35

单链表总结篇的相关文章

单链表反转总结篇

单链表反转总结篇 转自https://www.cnblogs.com/byrhuangqiang/p/4311336.html 单链表的反转是常见的面试题目.本文总结了2种方法. 1 定义 单链表node的数据结构定义如下: class ListNode { int val; ListNode next; ListNode(int x) { val = x; next = null; } } 2 方法1:就地反转法 2.1 思路 把当前链表的下一个节点pCur插入到头结点dummy的下一个节点中

数据结构第三篇——线性表的链式存储之单链表

线性表的链式存储结构的特点是用一组任意的存储单元来存储线性表的数据元素,这些单元可以分散在内存中的任意位置上,其在物理上可以是连续的,也可以是不连续的.具有链式存储结构的线性表称为线性链表. 为了表示出每个数据元素与其后继之间的关系,除了存储数据元素本身的信息之外,还需存储指示其直接后继的信息.这可以用一个结点(node)来完整的表示. 将节点中存储数据元素本身信息的域称为数据域:存储其直接后继位置的域称为指针域.指针域中存储的信息称作指针或链. 一般情况下,链表中每个结点可以包含若干个数据域和

单链表的基本操作(第一篇)

  学习数据结构的笔记 1.在线性表的链式存储中,头指针与头结点之间的根本区别以及头结点与开始结点的关系: 链表的头指针一般指向其第一个结点,他有标识链表的作用.头结点的作用在于统一相关操作,头结点的数据域一般没有意义,在某些情况下可以存放链表长   度.如果链表含有头结点,无论链表是   否为空,头指针均不为空.开始结点也就是链表中存储数据的第一个结点,它是头结点后边的第一个结点. 2.比较顺序表和链表各自的特点: (1)存储分配的方式:顺序表的存储空间是静态分配的.链表的存储空间是动态分配的

单链表 知识点学习--Android地基系列(一)

嗯,看别人整理过,自己再做的笔记,题目都是常见的必考题目,嘻嘻嘻,单链 表的基础知识我就不写了,太多人写了. 看前注意!!!!!!!涉及C知识较多,C知识我以后再考虑是否写一篇附加文 可以辅助以后的Android必备地基系列博文 struct ListNode { int data; ListNode * Next; }; 1.求链表中结点个数 思路:若链表为空,返回0:循环判断链表下一个指针是否为空,no,长度++(初始化用unsigned int  length = 0),直到下一个为nul

单链表(兼具Boost单元测试)

这是“线性表系列”中的“链表系列”文章之一——单链表.关于“线性表系列”中的“顺序表系列”请转到:基于静态分配的数组的顺序表(兼具Boost单元测试),基于动态分配的数组的顺序表(兼具Boost单元测试). 对于单链表的介绍请参考网页. 对于单链表,我定义了一个这样的类LinkedList: 1 // linkedlist.h 2 #ifndef LINKEDLIST 3 #define LINKEDLIST 4 5 #include <iostream> 6 #include <cas

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

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

「C语言」单链表/双向链表的建立/遍历/插入/删除

最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了C语言的框架开发,了解了View(界面层).Service(业务逻辑层).Persistence(持久化层)的分离和耦合,一种面向过程的MVC的感觉. 而这一切的基础就在于对链表的创建.删除.输出.写入文件.从文件读出...... 本篇文章在于巩固链表的基础知识(整理自<C语言程序设计教程--人民邮电出版社>第十章),只对链表的概念及增删改查作出探讨,欢迎指教. 一.链表结构和静态/动态链表 二.单链表的建立与遍历

如何判断单链表是否存在环 &amp; 判断两链表是否相交

给定一个单链表,只给出头指针h: 1.如何判断是否存在环? 2.如何知道环的长度? 3.如何找出环的连接点在哪里? 4.带环链表的长度是多少? 解法: 1.对于问题1,使用追赶的方法,设定两个指针slow.fast,从头指针开始,每次分别前进1步.2步.如存在环,则两者相遇:如不存在环,fast遇到NULL退出. 2.对于问题2,记录下问题1的碰撞点p,slow.fast从该点开始,再次碰撞所走过的操作数就是环的长度s. 3.问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分

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

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