1、链表

链表(linked list)即使是一些包含数据的独立数据结构的(Node)集合.

链表中的每个节点通过链或指针链接在一起.

程序通过指针访问链表中的节点.

节点通常是动态分配的,但也有由节点数组构建的链表(即使这样,程序也是通过指针来遍历链表).

1.1 单链表

单链表中,每个节点包含一个指向链表下一节点的指针.链表最后一个节点的指针字段的值为NULL.提示链表后面不再有其他节点.

根指针,根指针指向链表的第一个节点,根指针只是一个指针,不包含任何数据.

//但链表节点的结构
typedef struct NODE {
struct Node *link;
int value;
} Node;

单链表的一些性质

链表不一定是顺序存储的,它的节点可能分部于内存的各个地方.

单链表可以通过链表从开始遍历链表知道结束位置,但无法从相反方向进行遍历.

1.2 在单链表中插入

我们怎么才能把一个新节点插入到有序单链表中呢?加入要把12插入到单链表.(如果链表中的值为 5, 10, 15)

思路:从链表的起始位置开始,跟随指针直到找到第一个值大于7的节点,然后把这个新值插入到那个节点之前的位置.

有一个问题,当我们找到第一个大于12的节点时,指针可能指向了15,我们无法直到已经遍历过的指针了,我们也无法返回.解决这个问题的方法就是始终保存一个指向链表当前节点之前的那个节点指针.

//插入到一个有序的单链表,函数的参数是一个指向链表第一个节点的指针以及需要插入的值.
#include <stdlib.h>
#include <stdio.h>
#include "ssl_node.h" #define FALSE 0
#define TRUE 1 int ssl_insert( Node *current, int new_value ) {
Node *previous;
Node *new;
//寻找正确的插入位置,方法是按顺序访问链表,直到到达其值大于或等于新插入的值
while( current->value < new_value ){
previour = current;
current = current->link;
}
//为新节点分配内存,并把新值存储到新节点中,如果内存分配失败,函数返回False
new = (Node *)malloc( sizeof( Node ) );
if( new == NULL )
return FALSE;
new->value = new_value;
//把新节点插入到链表中,并返回TURE
new->link = current;
previous->link = new;
return TURE;
}
//调用
result = ssl_insert( root, 12 );

以上函数是存在问题的

插入20时,while 会越过链表的尾部.并对一个NULL指针执行间接访问操作. 我们没有对current 指针判空,在while语句中直接对current取value是不对的.对空指针间接引用是非法的.

所以 while( current != NULL & current->value < value ) 时继续循环

插入3时, 为了在链表的起始位置插入一个节点,函数必须修改指针.但是,函数不能反问变量root. 修正这个问题最容易的方法是把 root 声明为全局变量,这样插入函数就能修改它.不幸的是,这是最坏的一种方法.因为这样一来函数只对这个链表起作用了

稍好的解决方法是把一个指向root的指针作为参数传递给函数.然后使用间接访问. 函数不仅可以获得 root (指向链表第一个节点的指针,也就是根指针)的值,也可以向它存储一个新的指针值. 这个参数的类型是什么呢? root 是一个指向 Node 的指针, 所以参数的类型应该是Node **, 也就是一个指向Node 的指针的指针.

#include <stdlib.h>
#include <stdio.h>
#include "ssl_node.h" #define FALSE 0
#define TRUE 1
//插入到一个有序链表,函数的参数是一个指向链表根指针的指针,以及一个需要插入的新值
int ssl_insert( Node **rootp, int new_value) {
Node *current;//当前指针
Node *previous;//前一个指针
Node *new;//新节点指针 //得到一个指向第一个节点的指针
current = *rootp;
previous = NULL;//初始化previous //寻找正确的插入位置,方法是按序访问链表,直到达到一个其值大于或等于新值的节点
while ( current != NULL && current->value < new_value) {
previous = current;
current = current->link;
} //为新节点分配内存,并把新值存储到新的节点,如果内存分配失败.函数返回FALSE
new = (Node *)malloc( sizeof( Node ));
if (new == NULL) {
return FALSE;
}
new->value = new_value; //把新节点插入到链表中,并返回 TURE
new->link = current;
if ( previous == NULL) {//用于检测新值是否应该添加到链表的起始位置
*rootp = new;
}else {
previous->link = new;
} return TRUE;
}

终极优化

把一个节点插入到链表的起始位置必须作为特殊情况进行处理吗?毕竟我们此时插入新节点需要修改的指针是根指针,对于任何其他节点,对指针进行修改时实际修改的是前一个节点的link 字段. 这两个看上去不同的操作实际上是一样的.

消除特殊情况的关键在于:链表中的每个节点都有一个指向它的指针. 对于第一个节点,这个指针是根指针,对于其他节点,这个指针是前一个节点的link字段.重点在于每个节点都有一个指针指向它.至于指针是否位于某个节点之内是无关紧要的.

取得当前节点内部的link字段的地址也是很方便的: &current->link

#include <stdlib.h>
#include <stdio.h>
#include "ssl_node.h" #define FALSE 0
#define TRUE 1
/**
把头指针和节点内指针同样对待,就不用对插入第一个节点之前的情况特殊对待了 @param linkp 指向头指针的指针
@param new_value 新值
@return 插入结构 1成功,0失败
*/
int ssl_insert_1( register Node **linkp, int new_value){
register Node *current;
register Node *new; //寻找正确的插入位置,方法是按序访问链表,直道到达一个其值大于或等于新值的节点
while ( (current = *linkp) != NULL && current->value < new_value) {
linkp = &current->link;
} //为新节点分配内存,并把新值存储到新节点中,如果内存分配失败,函数返回FALSE
new = (Node *)malloc( sizeof( Node) );
if (new == NULL) {
return FALSE;
}
new->value = new_value; //在链表中插入新节点
new->link = current;
*linkp = new;
return TRUE
}

C和C指针小记(十七)-使用结构和指针-链表的更多相关文章

  1. C和C指针小记(十五)-结构和联合

    1.结构 1.1 结构声明 在声明结构时,必须列出它包含的所有成员.这个列表包括每个成员的类型和名称. struct tag {member-list} variable-list; 例如 //A s ...

  2. 结构体指针,C语言结构体指针详解

    结构体指针,可细分为指向结构体变量的指针和指向结构体数组的指针. 指向结构体变量的指针 前面我们通过“结构体变量名.成员名”的方式引用结构体变量中的成员,除了这种方法之外还可以使用指针. 前面讲过,& ...

  3. C和C指针小记(六)-基本声明、指针声明、typedef 、常量、作用域、链接属性、存储类型、static

    1.变量的声明 声明变量的基本形式: 说明符号(一个或者多个) 声明表达式列表 说明符 (specifier) 包含一些关键字,用于描述被声明的标识符的基本类型,它也可用户改变标识符的缺省存储类型和作 ...

  4. C语言--- 高级指针2(结构体指针,数组作为函数参数)

    一.结构体指针 1. 什么是结构体指针?指向结构体变量的指针     结构体:     typedef  struct stu{                          char name[ ...

  5. Leetcode 2. Add Two Numbers(指针和new的使用)结构体指针

    ---恢复内容开始--- You are given two non-empty linked lists representing two non-negative integers. The di ...

  6. C与指针(结构体指针,函数指针,数组指针,指针数组)定义与使用

    类型 普通指针 指针数组(非指针类型) 数组指针 结构体指针 函数指针 二重指针 定义方式 int *p; int *p[5]; int (*p)[5]; int a[3][5]; struct{.. ...

  7. ctypes 操作 python 与 c++ dll 互传结构体指针

    CMakeLists.txt # project(工程名) project(blog-3123958139-1) # add_library(链接库名称 SHARED 链接库代码) add_libra ...

  8. python 传递结构体指针到 c++ dll

    CMakeLists.txt # project(工程名) project(xxx) # add_library(链接库名称 SHARED 链接库代码) add_library(xxx SHARED ...

  9. 【C语言入门教程】7.3 结构体指针的定义和引用

    C 语言中指针的操作非常灵活,它也能指向结构体变量对结构体变量进行操作.在学习结构指针之前,需要再次加深对指针的认识.声明指针变量时所使用的数据类型修饰符实际上的作用是定义指针访问内存的范围,如果指针 ...

随机推荐

  1. 在IIS7上导出所有应用程序池的方法批量域名绑定(网站绑定)

    资料来源: http://www.2cto.com/os/201410/341882.html 一点经验:导出配置文件后,建议打开看看,如果有需要调整的需要做修改. 在IIS7+上导出所有应用程序池的 ...

  2. nginx(二)支持websocket配置

    在默认的配置nginx.conf文件中做如下配置改动 一.http域的设置 http { include mime.types; default_type application/octet-stre ...

  3. Delphi如何处理在进行大量循环时,导致的应用程序没有响应的情况

    一般用在比较费时的循环中,往往导致应用程序没有响应,此时在比较费时的程序体中加入Application.ProcessMessages即可解决,该语句的作用是检查并先处理消息队列中的其他消息. 例如, ...

  4. 快速开发项目,用到的工具:UI 设置利器 sketch

    需求设计: axaure8.0 tool: teambition/石墨.幕布. 接口管理tool(后端开发接口,pc,m,app使用) https://www.eolinker.com/#/ ui 设 ...

  5. .net core 2.0 虚拟目录下载 Android Apk 等文件

    当Android 文件 Apk 放在Asp.net core wwwroot 虚拟目录下面.访问是 404,设置Content-Type类型 app.UseStaticFiles(); //设置实际目 ...

  6. FasterRCNN 提升分类精度(转)

    近年来,随着深度学习的崛起,计算机视觉得到飞速发展.目标检测作为计算机视觉的基础算法,也搭上了深度学习的快车.基于Proposal的检测框架,从R-CNN到Faster R-CNN,算法性能越来越高, ...

  7. 对世界首款“人工智能”ERP系统HUE的初步了解 - AI ERP - WAP - 万革始

    偶然的机会,刚好在查找机器人王国[奇妙的餐厅]的时候,看到开发[光的王国],[奇妙的宾馆],[奇妙的餐厅]等豪斯登堡集团在3月17日采用了这个传说中的世界首款人工智能ERP系统AI WORKS的下面4 ...

  8. ListFiles():返回Files类型数组,可以用getName()来访问到文件名。

    List():显示文件的名(相对路径) ListFiles():返回Files类型数组,可以用getName()来访问到文件名. 使用isDirectory()和isFile()来判断究竟是文件还是目 ...

  9. Go的json解析:Marshal与Unmarshal

    https://blog.csdn.net/zxy_666/article/details/80173288 https://www.jianshu.com/p/98965b3ff638

  10. tensorflow c/c++库使用方法

    tensorflow目前支持最好的语言还是python,但大部分服务都用C++ or Java开发,一般采用动态链接库(.so)方式调用算法,因此tensorflow的c/c++ API还是有必要熟悉 ...