Bliner'Site Bliner'Site

高树靡阴,独木不林。


  • 首页

  • 分类 10

  • 标签 36

  • 归档 214

  • 关于我

  • 搜索

标签:C

数据结构之线性表-单向循环链表的尾指针(下)-学习笔记-25

发表于 2018-11-24 | 分类 笔记&教程 | 评论数: 0 | 阅读次数: 42

引入

上一节,我们学习了尾指针,并且利用尾指针。尾指针可以轻松的操作头结点和尾结点,可以将两个单循环链表组成了一个单循环链表,我们今天再看看,尾指针还有什么其它玩法。

单链表中的环

首先要明白,单链表有环的状态是什么样子得

其实就是,尾指针指向了链表中的某个结点。

如何判断单链表中是否有环

方法 1

  • 设置 p 、q 两个指针
  • p 向前走,q 从头走,p 向前走尾部应该会到 NULL。
  • 每个结点,p 走的步数应该和 q 一样
  • 如果不一样,就像上面的图,p 的地址等于 q
  • 但是,p 走到3用了6步,q 则用了2步
  • 步数不相等,那么就存在环

方法 2

  • 设置 p 、q 两个指针
  • p 每走一步,q 就走两步,快慢指针
  • 快指针应该很快到 NULL
  • 如果 p==q 了,则存在环
阅读全文 »

数据结构之线性表-单向循环链表的尾指针(上)-学习笔记-24

发表于 2018-11-23 | 分类 笔记&教程 | 评论数: 0 | 阅读次数: 139

引入

我们学习了循环链表的基本操作,也学习了一个有趣的约瑟夫问题,我们之前说过有头指针也有尾指针,头指针指向头结点,尾指针指向尾结点。那么尾指针有哪些有趣的用法呢?

单循环链表的问题

我们知道,在单向循环链表中,我们有头指针

  • O ( 1 ) 的时间去找到第一个结点,因为 next 就是头结点
  • O ( n ) 的时间去找最后一个结点,因为第 n 个才是尾结点

如何在访问头结点和尾结点得时候,都是O( 1 )时间复杂度呢?

尾指针应运而生!

  • 尾指针指向的是尾节点
  • 而尾节点得下一个就是头结点

所以尾指针访问头结点和尾节点的时间都是 O ( 1 ) 。
撒花~~~

尾指针

阅读全文 »

数据结构之线性表-约瑟夫环-学习笔记-23

发表于 2018-11-23 | 分类 笔记&教程 | 评论数: 0 | 阅读次数: 18

引入

罗马占领乔塔帕特之后,39个犹太人与 Joseph 及1个朋友躲进山洞避难,39个人宁死也不愿意被敌人抓到,决定了一种自杀方式:

  • 41 个人排成一个圆圈(39个犹太人 + Joseph + 1 个朋友)
  • 第 1 个人开始报数,每报数到第3人,这个人就自杀
  • 然后再从下一个,也就是原来的第 4 人开始,数到第 3 人自杀
  • 直到所有人都自杀身亡为止

但是 Joseph 和朋友并不想死,所以就有如下那排

  • 朋友去了 16 号
  • Joseph 去了 31 号
  • 于是,逃过了死亡游戏

约瑟夫问题

那么这个有趣得约瑟夫和朋友逃难的问题跟我们得循环链表有什么关系呢?我们想用计算机帮助我们把41个人的自杀编号输出出来:

代码实现

阅读全文 »

数据结构之线性表-循环链表-学习笔记-22

发表于 2018-11-22 | 分类 笔记&教程 | 评论数: 1 | 阅读次数: 32

引入

我们讲了顺序存储结构、单链表、静态链表,今天我们学习一种新的链表,单循环链表,单循环链表很简单,其实就是在单链表的基础上,将头尾相连,形成一个单向环装循环。

单循环链表

我们知道,单链表非常有趣,虽然不连续,但却根据指针一个连着一个,但是单链表有一个问题,我们如果不从头结点出发,就无法访问所有结点。
解决方法也非常简单,就是把链表终端结点得指针由 NULL 改成指向头结点。也就是链表最后一个结点存储得指针为头结点得指针,也就是原来 head 存储的地址。
既然head 和 最后一个结点 都指向头结点,那么我们就称这种头尾相接得单链表位单循环链表。

单循环链表的特点

既然头尾相接,那么单循环链表有新增了下面几种特性

  • head 指向头结点,尾部也指向头结点
  • 判断空表得时候,只要头结点和头部指向得内容都是该结点本身,那么这个表就是空表。
  • 头结点即尾部,头结点指向头结点,head 指向头结点
  • 原来是 head->next 是否为 NULL,是就为空表。
  • 现在是 head 是否等于 head->next,即头结点指针指向它自己
  • 我们把最后一个结点得指针称为 rear
阅读全文 »

数据结构之线性表-静态链表的优缺点以及练习-学习笔记-21

发表于 2018-11-21 | 分类 笔记&教程 | 评论数: 2 | 阅读次数: 25

引入

按照惯例,我们学习了如何初始化、插入、删除一个静态链表,那么静态链表打底有什么优缺点呢?链表还有什么高级玩法呢?
我们一起来看看~

静态链表的优缺点

  • **优点:**插入和删除时,只需要求改游标,不需要移动元素,从而改进了顺序存储结构中需要大量移动元素的缺点。
  • **缺点:**没有解决连续存储分配带来得表长难以确定的问题。

总之,静态链表是一个很好的尝试,在没有动态创建、释放内存空间得情况下,利用数组,完成了静态链表。

练习

创建一个20个元素的动态链表,然后快速找到其中间结点。

阅读全文 »

数据结构之线性表-在静态链表中删除结点-学习笔记-20

发表于 2018-11-21 | 分类 笔记&教程 | 评论数: 0 | 阅读次数: 58

引入

我们知道了如何初始化一个静态链表,并且知道如何在静态链表中插入一个结点,今天我们来看看如何删除一个结点,并将删除得结点 Free 。

思路

我们先想一下,如果要移除静态链表中的一个结点,会发生什么。

  • 该结点的上一个结点找不到移除的这个结点了,链表断了
  • 移除的结点内得数据还有,游标指向的是其原来的下个结点
  • 移除的结点成了备用链表中的一个结点,0下标的第一个可用结点也需要修改

所以,我们总结如下得思路

  • 移除结点,找到前一结点,指向移除结点的后一结点
  • 清空移除的结点内的数据
  • 移除结点的游标改为0下标指向的第一个可用结点得下标
  • 0下标指向的第一个结点为移除的结点
阅读全文 »

数据结构之线性表-在静态链表中插入结点-学习笔记-19

发表于 2018-11-20 | 分类 笔记&教程 | 评论数: 0 | 阅读次数: 27

引入

我们说过动态链表是使用malloc( ) 和 free( )这两个函数来实现的,动态插入,动态释放。那么静态链表该如何实现这样的功能呢?

静态链表中插入数据

简单来说就是要分清楚哪些没有使用过,哪些已经在使用了。
我们说

  • 备用链表存放的是所有可以用的下标,用游标链接。
  • 数组的第一个元素,存放的是备用链表的第一个可用下标
    所以
    每次插入新节点,都可以从备用链表取得第一个结点作为待插入结点。

步骤分解
1、先获取0下标指向的备用链表的第一个可写入下标。
2、第一个可写入的结点的游标传递给0下标。
3、判断插入地址是否合法,不能小于1,不能大于结点长度+1的位置。
4、对第一个可写的节点的 data 赋值
5、通过循环从最后一个结点向前找到要插入的节点之前的结点
6、找到之后新结点的游标改成之前结点的游标
7、前一结点的游标指向新节点的下标。

阅读全文 »

数据结构之线性表-静态链表及其初始化-学习笔记-18

发表于 2018-11-16 | 分类 笔记&教程 | 评论数: 0 | 阅读次数: 69

引入

我们学习了线性表中的顺序存储结构、单链表以及他们的初始化、插入、查找、删除等操作,今天我们来看看,没有动态创建内存空间之前,人们是如何使用链表的~

静态链表

简单来说,我们将用数组描述的链表称为静态链表,这种描述方法叫做游标实现法。
我们知道,链表是由指针域和数据域两个部分组成,静态链表也差不多,但它们是由数据域和游标组成。因为是数组,所以描述时还有一个下标。

  • **数据域:**存放的是该静态链表中每个结点的数据。
  • **游标:**用于找到下一个结点,类似于指针。
    下标:
  • 0号下标存没有数据,游标存储着可以存放数据的下标。
  • max 号下标存储着该静态链表第一个结点的位置,类似于 head 指向头结点。
  • 其他下标存储的是当前结点数据和下一个结点的下标。

其实简单来说,因为不能动态创建内存空间,那就再顺序存储结构中设置了一个游标,游标类似于指针,存放的不是内存地址,而是下一个结点的下标。

阅读全文 »

数据结构之线性表-顺序存储结构和单链表的对比及效率分析-学习笔记-17

发表于 2018-11-16 | 分类 笔记&教程 | 评论数: 0 | 阅读次数: 41

引入

我们基本学习了如何创建、删除、插入、修改一个单链表,那么单链表跟顺序表比真的高效嘛?单链表又适用于什么情况呢?单链表跟顺序表的优缺点呢?我们一起来看看!

效率观察

我们发现,无论是插入还是删除单链表中的元素,其实就分两步

  • 遍历查找第 i 个元素
  • 实现插入和删除

从算法的角度很容知道它们的时间复杂度都是 O(n);

那么单链表和顺序表岂不是都一样了?既然都是 O(n),那链表的优势在哪呢?

对比

从第 i 个位置开始,连续插入10个元素

对于顺序存储结构

  • 没插入一个都要移动 n-i 个位置
  • 每次都是 O(n)

对于链表

  • 找到第 i 个位置的指针,此时时间复杂度为 O(n)
  • 接下来的赋值移动指针的时间复杂度为 O(1)

所以,对于删除和操作频繁的操作,单链表的效率就越高。

阅读全文 »

数据结构之线性表-尾插法创建单链表-学习笔记-16

发表于 2018-11-14 | 分类 笔记&教程 | 评论数: 0 | 阅读次数: 37

引入

我们学习了用头插法和尾插发创建一个单链表,今天我们在学习如何删除整个单链表。

删除整个单链表

其实就是再内存中将它释放掉,留出空间给其它软件使用。
整表删除思路:

  • 声明结点 p 和 q
  • 第一个结点给 p,第二个结点给 q
  • 释放完 p,将 q 指向的给 p
  • 释放完 q,将 p 指向的给 q
  • 循环执行,直到完全释放完毕

代码实现

#include <stdio.h>
#include <stdlib.h>
#define LEN sizeof(struct Student)
struct Student{
    int num;
    char name[20];
    float score;
    struct Student *next;
};

struct Student *create(void){
    struct Student *a,*b,*head;
    a=(struct Student *)malloc(LEN);  //创建结点
    head=(struct Student *)malloc(LEN);
    b=head;  //b 是指向尾部的节点
    printf("请输入学生信息:\n");
    scanf("%d %s %f",&a->num,a->name,&a->score);
    while(a->num!=0){
        b->next=a;
        b=a;
        a=(struct Student *)malloc(LEN);
        scanf("%d %s %f",&a->num,a->name,&a->score);
    }
    b->next=NULL;
    return head;
}

void print(struct Student * p){
    p=p->next;
    while(p!=NULL){
        printf("%d号%s的成绩是:%3.1f\n",p->num,p->name,p->score);
        p=p->next;
    }
}

void delete_p(struct Student * p){
    struct Student *a,*b;
    a=p->next;  //先让 a 指向第一个结点
    while(a){
        b=a->next;  //b 记住 a 的下一个结点
        free(a);  //释放 a
        a=b;  //a 成为第下一个结点
    }
    p->next=NULL;
}

int main(){
    struct Student* stu_p;
    stu_p=create();
    print(stu_p);
    delete_p(stu_p);
    print(stu_p);
    return 0;
}
阅读全文 »
上一页 1 ... 4 5 6 ... 14 下一页
Bliner

Bliner

214 日志 10 分类 36 标签
RSS

推荐阅读

关于GTD中项目“复盘”的一想法
© 2008 - 2026 Bliner
鲁ICP备13021673号