zoukankan      html  css  js  c++  java
  • 单链表---邻接表

    近段时间在学习线段树,二叉树,字典树,网络流,图,都需要动态内存分配和建立链式结构,每次都是要看好长时间,一个朋友告诉我,好好看看单链表,把最基础的抓住,其他的就会迎刃而解。

    动态内存分配对建立表、树、图和其他链式结构是特别有用的。

     单链表       

    结构体声明类型:

    struct node

    {

      int date;

      node *next;

    };

    单链表的建立

    struct node *p, *head;

    head=NULL;

    p=(struct node *)malloc(sizeof(struct node));//为节点分配内存空间

    scanf("%d", &p->date);//把数据存储到节点中或者直接赋值 p->date=a;

    p->next=head; head=p;//把节点插入到链表中,此方法为从头插入,如果你输入的是5 4 3 2 1,那么里面的顺序会是 1 2 3 4 5

    单链表的遍历

    struct node *p;//定义一个指针在链表之间移动;

    p=head;//首先指向表中的第一个元素

    while(p)//如果没有表尾就执行循环

    {

      printf("%d", p->date);//输出p所指节点的元素值

      p=p->next;//让p指向下一个节点

    }

     单链表的插入.

    一般从中间插入.此时就应该找到要插入的是哪一个结点后面,则称此节点为要插入节点的前驱节点,用pre表示

    struct node *p, *pre;

    p=(struct node *)malloc(sizeof(struct node));//创建一个新结点

    p->next=pre->next;//将新节点的next指向前驱节点next指向的那个节点

    pre->next=p;//将前驱节点的next指针指向新节点

    单链表的删除

    删除p点,此时我们就要找到p点的前驱节点

    if(pre==NULL)

      head=head->next;//如果要删除的是第一个节点,则改变头指针的方向

    else

      pre->next=p->next;//否则改变前一个节点,使它绕过要删除的节点

    free(p);//释放要删除的p这个节点的空间

     邻接表      

    写过之后我仍然无法明白,邻接表的原理,再接再厉;

    朋友不建议我直接用vector 类,他说我这样用现成的会阻挡我的步伐,虽说现在进度是快了点,但如果最基础的如何建立都不明白,又何谈灵活的应用呢,根本转化不成自己的东西,他说让我先从最基础的学起,尽量不用那些C++里面的函数库,他说让我自己实现,这样我的代码和思维能力就会有很大的提高,加油!

    说实话,我觉得邻接表很神奇,如果是我我可能就不会如此建立,这是参考别人代码,才知道这样建立的

     邻接表,其实也要结构体类型声明

    struct node

    {

    int date;

    node *next;

    }G[N];

    int head[N];

    memset(head, -1, sizeof(head));

    int cnt=0;

    void addedge(int a, int b)

    {

      G[cnt].date=b;

      G[cnt].next=head[a];

      head[a]=cnt;

      cnt++;

    }

    说实话,我是看了两天才明白了最基础的,智商不够啊,很可惜,没有人真正的指点我,不过我搜了百度文库,看不明白;

    给你一组数据代表a与b相连

    1 2

    1 4

    2 4

    2 3

    3 4

    cnt 0          1             2           3            4           
    1 1 2 2 3
    G[cnt].date=b 2 4 4 3 4
    next=head[a] -1 0 -1 2 -1

    head[a]现在的值

    也就是cnt++之后的值

    head[1]=0 head[1]=1 head[2]=2 head[2]=3 head[3]=4

    我们建立的邻接表其实是这样的(单向的)

    1  与2 4相连

    2  与4 3相连

    3  与4   相连

    head[0]=-1;

    head[1]=1;

    head[2]=3;

    head[3]=4;

    head[4]=-1;

    你们又没有发现什么,类似与栈,也就是说cnt 0->1  如果遍历的话,就for(j=head[a]; j!=-1; j=G[j].next) 一般a从start开始一般是1,到end;这时候观察一下,head[1]=1;此时G[j] 刚好就是G[1]也就是与1相连的4,之后j=0;刚好是与1相连的2;类似与栈,我们将1压入栈底,之后压入4;所以我们寻找的时候首先搜索到的head[a]最后进栈的,之后再向前推,由此,你明白为什么G[cnt].next=head[a];

    head[a]=cnt;也就是说这里的G[cnt].next存的是上一个与u相连的值,而head[a]=cnt就是记录此时的下标,方便为下一个的next赋值;

    观察紫色与紫色数字之间的关系,红色与 红色数字之间的关系,再 看他们这两行 的‘a’值,竟然是相同的

    而且head[a]=cnt;就本列来说; 所以你就会明白 其实next=head[a]的含义就是建立关系,即使是在G数组中

    我建立的是单向的,如果是双向路这样做也可以,只用添加反边就行了;

      通俗的说 与节点 a相连的第一条边是G[cnt].date,那么‘a’相连的下一条边是G[cnt].next;而G[cnt].next又等于下一条边的数组的下标

    G[cnt1].next=head[a]; head[a]=cnt2; 你们看看领悟领悟  这里cnt1 与cnt2 就是与 ‘a’相连的边的数组的下标;

    这里推荐一个博客,写的简洁明了,我搜的时候搜到的;http://blog.csdn.net/u014303647/article/details/38865357

     大家可以观察一下,next这一行, 与cnt这一行的关系。其实就可以发现next其实代表与  ‘1’  相连的第一个数是 ‘2’  第二个数也就是(next)下一个数是 ‘4’;这就是为什么a不存入其中的原因;

    同理 与‘2’ 相连的是‘4’ 之后的是‘3’;依次进入表中,看过这个大家也就明白为什么next=head[a]了吧,每次head[a]都会更新为cnt现在的值也就是记录,与‘a'相连的这个数‘b’所存在的位置;

    当我们遍历的时候,就可通过寻找G[i].next来寻找与‘a’相连的其他数;因此每次addage这个函数里面 可以总结两条 更新过后的head[a]=cnt;

    之前用的是#include<vector>这个头文件,但是其实这样不好,本末倒置了,如果我先理解上面那一种,我理解vector类就会更清晰,但是先理解vector类在理解基础的建立过程就会很艰难;

    (1)vector<int>a;//相当于申请一个一维数组

    a.push_back(i);//压入

    a.size();//得到长度

    a.clear();//清空

    (2)vector<int>G[N];相当于vector<vector<int >>G//相当于申请一个二维数组

    G.resize(n+1);//申请内存

    G[i].push_back(j);

    G[i].size();

    G[i].clear();

  • 相关阅读:
    安卓系统隐藏滚动条
    jquery 失去焦点时输入框为空时自动填写默认内容
    移动端左右滑动代码
    [转]C#使用FFmpeg 将视频格式转换成MP4示例
    [转]Windows 使用ffmpeg将MP4视频转换为m3u8格式
    [转]搭建flutter开发环境
    [转]ios webview下纯JS实现长按
    [转]SQLServer查询数据库各种历史记录
    [转]Java多线程学习(总结很详细!!!)
    [转]安卓加固之so文件加固
  • 原文地址:https://www.cnblogs.com/wazqWAZQ1/p/4729025.html
Copyright © 2011-2022 走看看