【数据结构】 链表知识点整理

首先是链表的定义:

typedef struct NODE{
    struct NODE *next;
    int value;
}Node,*Linklist;

其中 Linklist为指向Node的指针;

接下来是几个常用的函数:

一.链表的初始化:

int Linklist_init(Linklist *L)
{
*L = (Linklist)malloc(sizeof(Node));
if(!(*L))
{
printf("创建失败");
return FALSE;
}
(*L)->next = NULL;
return TRUE;
}

问:为什么需要使用Linklist *L

答: 在局部函数中进行用指针修改变量值,  如果我们想修改一个int a的值 需要传入int *a; 即指向int的指针;

同理, 我需要给一个Linklist(指向Node的指针)赋值, 就需要修改Linklist的指针。 即二级指针;

实际测试, 当写成Node *L;L = (Node *)malloc(sizeof(Node));   时不会报错, 但是L->next 并没有被正确赋值。 当试图对链表操作时系统会崩溃;(猜测是内存被分配了 却无法被指向。)

转自CSDN:

如果是使用一级参数传递,首先是main函数中定义一个Node类型的指针,这个指针用list表示,C语言在定义指针的时候也会分配一块内存,一般会占用2个字节或4个字节,现在在大部分的编译器中占用4个字节,这里用4个字节算。在这4个字节的内存中,没有任何值,所以这个指针不指向任何值。然后传递到函数init_linkedlist中,在init_linkedlist函数中,编译器首先为形参list分配一个临时指针内存块,而语句 list = (LinkedList)malloc(sizeof(Node));  中函数malloc分配一块内存,并向该程序返回一个指向这块内存的指针,这样形参list就有值了,在list所表示的临时内存区域中填入刚刚分配的内存的这块内存的地址,假设为0x10086,这样使用(*list)就可以访问这块内存(0x10086)中的内容了。此时在函数init_linkedlist中list所代表的这块内存中的内容是有值的,

但是现在的list只是占据了一个零时的内存空间,这种改变并不能反映到main函数中,init_linkedlist函数执行完了,临时的list内存块就被回收了,这样刚刚分配的内存块的地址0x10086没有被记录下来。而我们如果要初始化main函数中的链表list的话,就必须记录记录下这块内存空间(0x10086)。

然后来考虑 二级指针的情况:即 *L = (Node *)malloc(sizeof(Node));

函数的参数是一个二级指针,同样,在执行调用这个函数的时候,临时分配一个指针,这个指针占据一个占用4个字节的内存块(函数执行完要回收的),同时这个临时指针L指向主函数main中定义的list指针,这里假设主函数main中的list指针在内存中的地址为0x12306,

其中L是一块临时内存,list是主函数main的中定义的一个指针,此时list代表的内存块还没有初始化。下面执行内存分配的代码

malloc函数分配了一块内存空间,假设地址为0x10010,由于L指向list所代表的内存块,所以*L等价于list,这样将malloc函数分配的内存块赋值给*L就相当于执行语句

这样在函数init_linkedlist中分配的一段内存也就能在main函数中反映出来了,main函数中list代表的内存块的就指向了新分配的内存,链表初始化完成。

简而言之: malloc所开辟的空间 需要通过一个钥匙(指针) 来访问;子函数的指针传递,传进去的时指针,修改的却是指针指向的内容。 同理 我们只有传进去一个指针的指针,才能修改指针的指针指向的内容(即指针)

然而我更喜欢这种写法。(return大法好——Saber是最强的)

Node* Link_init()
{
    Node *Saber;
    Saber = (Node*)malloc(sizeof(Node));
    Saber ->link = NULL;
    return Saber;
}

感觉没那么麻烦。 0.0

二. 清空链表:

int Linklist_clean(Linklist *L)
{
    Linklist p,q;
    if(!(*L)->next)
    {
        return FALSE;
    }
    p=(*L)->next;
    (*L)->next = NULL;
    while (p)
    {
        q =p->next;
        free(p);
        p=q;
    }
    printf("已经清空\n");
    return TRUE;
}

三. 销毁链表:

int Linklist_go_die(Linklist *L)
{
    Linklist p;
    while(*L)
    {
        p = *L;
        (*L) = (*L)->next;
        free(p);
    }
    printf("已经销毁\n");
    return TRUE;
}

五.查找链表中是否有整数data:

int Linklist_search(Linklist L,int data)
{
    L = L->next;
    while(L)
    {
        if(data == L->data)
        {
            return TRUE;
        }
        L=L->next;
    }
    return FALSE;
}

五.在表尾添加一个元素:

int Linklist_insert(Linklist L,int e)
{
    Linklist s;
    s = (Linklist)malloc(sizeof(Node));
    s->data = e;
    s->next = NULL;
    while(L->next)
    {
        L = L->next;
    }
    L->next = s;
    return TRUE;
}

六.删除链表中第i个元素:

void Linklist_free(Linklist L,int Number)
{
    Linklist Aid;
    if(Number <= 0)
    {
        printf("数据异常");
        return;
    }
    while(L&&Number)
    {
            Aid = L;
            Number--;
            L = L->next;
    }  /*  跳出循环有两种可能:  1. 表到尾部而Number依然大于零。  2. 表未到尾部, Number==0 此时Aid刚好为要删除结点的前一个结点  */
    if(Number>0)
    {
            printf("异常\n");
            return;
    }
    else
    {
            Aid->next = L->next;
            free(L);
    }
}

七.去除链表中重复的数据:

void Linklist_filter(Linklist *L)
{
    Linklist Aid;
    Linklist p = *L;
    Linklist_init(&Aid);
    while(p = p->next)
    {
        if(FALSE == Linklist_search(Aid,p->data))
        {
            Linklist_insert(Aid,p->data);
        }

    }
    Linklist_clean(L);
    *L = Aid;
}

于是写出一段程序:

创建一个链表,输入一些值, 去除其中重复的值:

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

int main()
{
    Linklist L;
    int next = 0;
    Linklist_init(&L);
    printf("输入一组数据,输入-1退出\n");
    while(next != -1)
    {
        scanf("%d",&next);
        if(next != -1)
         {
             Linklist_insert(L,next);
         }
    }
    print_Linklist(L);
    Linklist_filter(&L);
    print_Linklist(L);
    return 0;
}

原文地址:https://www.cnblogs.com/tao-zhu-forever/p/8778872.html

时间: 2024-10-09 14:31:24

【数据结构】 链表知识点整理的相关文章

链表 知识点整理

链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer).由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1). 使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理.但是链表失去了

常见数据结构与算法整理总结(上)

数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.算法是为求解一个问题需要遵循的.被清楚指定的简单指令的集合.下面是自己整理的常用数据结构与算法相关内容,如有错误,欢迎指出. 为了便于描述,文中涉及到的代码部分都是用Java语言编写的,其实Java本身对常见的几种数据结构,线性表.栈.队列等都提供了较好的实现,就是我们经常用到的Java集合框架,有需要的可以阅读这篇文章.Java - 集合框架完全解析 一.线性表 1.数组实现 2.链表 二.栈与队列 三.树

数据结构基础知识整理(目录)

[数据结构第一周]最大子列和问题整理 [数据结构第二周]线性表知识点整理 [数据结构第二周]堆栈知识点整理 [数据结构第二周]队列知识点整理 [数据结构第三周]树知识点整理(上) [数据结构第四周]树知识点整理(下)[二叉搜索树] [数据结构第四周]树知识点整理(下)[平衡二叉树] [数据结构第四周]树知识点整理(下)[堆] [数据结构第五周]图(上) [数据结构第六周]图(下)[最短路径问题] [数据结构第七周]排序(上) [数据结构第八周]排序(下)[快速排序]

常见数据结构与算法整理总结(下)

这篇文章是常见数据结构与算法整理总结的下篇,上一篇主要是对常见的数据结构进行集中总结,这篇主要是总结一些常见的算法相关内容,文章中如有错误,欢迎指出. 一.概述 二.查找算法 三.排序算法 四.其它算法 五.常见算法题 六.总结 一.概述 以前看到这样一句话,语言只是工具,算法才是程序设计的灵魂.的确,算法在计算机科学中的地位真的很重要,在很多大公司的笔试面试中,算法掌握程度的考察都占据了很大一部分.不管是为了面试还是自身编程能力的提升,花时间去研究常见的算法还是很有必要的.下面是自己对于算法这

数据库设计教程系列——相关知识点整理

一.教程概述 此数据库设计教程是笔者参考网上资料.相关书籍,以及加上自己多年做数据库设计相关工作的经验积累写就. 数据库设计教程在网上已经有大量类似的资料,并且该领域有不少专业书籍,珠玉在前,心有戚戚. 但这作为唯心六艺之一,我还是希望能够在整理知识的同时,写出自己的一些内容,如果能够对读者 有所帮助,那就最好不过了,谢谢. 本教程主要基于关系型数据库进行讲解,对于维度数据库也会视情况有所涉猎. 下面是整个教程涉及的知识点整理,在撰写教程的过程中,如果有改动,也会调整更新此图. 二.知识点整理

asp.net mvc 3.0 知识点整理 ----- (2).Controller中几种Action返回类型对比

通过学习,我们可以发现,在Controller中提供了很多不同的Action返回类型.那么具体他们是有什么作用呢?它们的用法和区别是什么呢?通过资料书上的介绍和网上资料的查询,这里就来给大家列举和大致的概括下. (1). ActionResult(base):最基本的Action类型,返回其他类型都可以写ActionResult. (2). ContentResult:返回ContentResult用户定义的内容类型. public ActionResult Content() { return

【知识点整理】Oracle中NOLOGGING、APPEND、ARCHIVE和PARALLEL下,REDO、UNDO和执行速度的比较

[知识点整理]Oracle中NOLOGGING.APPEND.ARCHIVE和PARALLEL下,REDO.UNDO和执行速度的比较 1  BLOG文档结构图 2  前言部分 2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~O(∩_∩)O~: ① 系统和会话级别的REDO和UNDO量的查询 ② NOLOGGING.APPEND.ARCHIVE和PARALLEL下,REDO.UNDO和执行速度的比较(重点)   Tips: ① 本文

【Android 面试基础知识点整理】

针对Android面试中常见的一些知识点整理,Max 只是个搬运工,感谢本文中引用文章的各位作者,给大家分享了这么多优秀文章,对于其中的解析,是原作者个人见解,有错误和不准确的地方,也请大家积极指正. 本文将持续更新,同时我也将其放在Github上:Point-of-Android 同时可以看Max的个人博客:海上钢琴师 Android中的异步任务机制 Android中AsyncTak的使用与源码分析 http://blog.csdn.net/bboyfeiyu/article/details/

·DP」知识点整理

一.最长公共子序列(LCS Longest Common  Subsequence) 第一,先说区别,最长公共子串和最长公共子序列是不一样的. 最长公共子串不许是连续的,而最长公共子序列可以是不联系的. 网络上解释的子序列: 一个字符串S,去掉零个或者多个元素所剩下的子串称为S的子序列.最长公共子序列就是寻找两个给定序列的子序列,该子序列在两个序列中以相同的顺序出现,但是不必要是连续的. 例如 X=ABCBDAB Y=BDCABA BCA是X和Y的一个公共子序列,但是不是X和Y的最长公共子序列,