数据结构---概念、数据与数据之间的关系(逻辑结构、物理结构)、基本功能、数据结构内容、单向链表(该奶奶、对象、应用)

数据结构

在数据结构部分,研究数据在内存中如何存储。

数据存储的形式有两种:变量和数组(数据结构的顺序表)。

一、什么是数据结构?

数据类型被用来组织和存储数据。

程序设计 = 数据结构 + 算法

二、数据与数据之间的关系

1、逻辑结构

数据元素与元素之间的关系。

1)集合:元素与元素之间平等的集合关系。

2)线性结构:元素与元素之间存在一对一的关系(eg. 顺序表、链表、队列、栈)。

3)树形结构:元素与元素之间存在一对多的关系(eg. 二叉树)。

4)图形结构(网状结构):元素与元素之间存在多对多的关系。

内存为线形存储结构。

2、物理结构

数据元素在计算机内存中的存储方式。

1)顺序结构:在内存中选用一段连续的内存空间进行存储。

特点:(1) 数据访问方便 (算法复杂度O(1) )。

(2) 插入和删除数据时需要移动大量数据。

(3) 需要域内存分配 (连续的) 。

(4) 可能造成大量内存碎片 (分为内内存碎片和外内存碎片两种 )。

|--------|--------------------------------------------------------|
| 内存碎片分类 | 内存碎片特点 |
| 内内存碎片 | 操作系统已分配给程序的内存中部分小内存空间不能再被使用,例如结构体数据类型存储时的中间空闲块 |
| 外内存碎片 | 内存中存在大量不连续的空闲块,因分散在内存的不同位置而不能合并成一块连续的大空间,导致程序无法被加载到内存中 |

2)链式结构:可以在内存中选用一段不连续的内存空间进行存储。

给内存元素后加上指针,指针指向元素访问下一个元素。

特点:(1) 数据访问必须从头遍历 (算法复杂度O(n) );

(2) 插入和删除元素方便;

(3) 不需要与内存分配 (离散的),是一种动态内存操作 (只要有部分内存空间能放下部分数据,直至存放完全部数据就行)。

3)索引结构:将要存储的数据的关键字和存储位置之间构建一个索引表。

4)散列结构(哈希结构):将数据的存储位置与数据元素之间的关键字建立起对应的关系( 哈希函数 )。

索引结构与散列结构都用于快速定位数据。

三、基本功能

指针、结构体、动态内存分配。

四、数据结构内容

数据结构内容包含:顺序表、链式表(单向链表、双向链表、循环链表、内核链表)、栈、队列、二叉树、哈希表、常用算法。

五、单向链表

1、概念

单向链表是一种常见的线形数据结构,由多个节点组成,每个节点包含两部分:

1) 数据域:存储结点本身的信息(如数值、字符等)。

2) 指针域:存储下一个结点的地址,用于指向链表中的下一个结点。

示意图如下:

特点:整个链表的访问需从第一个结点开始,依次通过指针域找到下一个节点,最后一个结点的指针域为空指针(NULL),单向链表无法访问前一个结点。

2、链表的对象

链表的对象是存储数据的对象。

链表对象的属性特征(变量):第一个结点、结点的个数。

链表对象的行为(函数):创建链表对象、插入数据、删除数据、修改数据、查找数据、销毁链表。

3、单项链表的应用

1)单向链表的封装

(1) 封装结点(存放在声明文件中)

cs 复制代码
/*链表的结点类型*/
typedef struct node
{
    Data_type_t data;
    struct node *pnext;
}Node_t;

(2) 封装对象(存放在声明文件中)

cs 复制代码
/*链表对象类型*/
typedef struct link
{
    Node_t *phead;
    int clen;
}Link_t;

(3) 创建单向链表函数封装

cs 复制代码
/*创建单向链表*/
Link_t *create_link()
{
    Link_t *plink = malloc(sizeof(Link_t));
    if(NULL == plink)
    {
        printf("malloc error!\n");
        return NULL;
    }

    plink->phead = NULL;
    plink->clen = 0;

    return plink;
}

(4) 单向链表---头部插入数据函数封装

cs 复制代码
/*向单向链表的头部插入数据*/
int insert_link_head(Link_t *plink, Data_type_t data)
{
    //申请结点
    Node_t *pnode = malloc(sizeof(Node_t));
    if(NULL == pnode)
    {
        printf("malloc error!");
        return -1;
    }
    //初始化结点
    pnode->data = data;
    pnode->pnext = NULL;


    //头插2步插入结点
    pnode->pnext = plink->phead;
    plink->phead = pnode;

    plink->clen++;
    return 0;
}

(5) 单向链表---遍历函数的封装

cs 复制代码
//遍历
void link_for_each(Link_t *plink)
{
    Node_t *ptmp = plink->phead;
    while(ptmp != NULL)
    {
        printf("%d ", ptmp->data);
        ptmp = ptmp->pnext;
    }
    printf("\n");
}

(6) 单向链表---查找函数的封装

cs 复制代码
//查找
Node_t *find_link(Link_t *plink, Data_type_t mydata)
{
    Node_t *ptmp = plink->phead;

    while(ptmp != NULL)
    {
        if(mydata == ptmp->data)
        {
            return ptmp;
        }
        ptmp = ptmp->pnext;
    }
    return NULL;
}

(7) 单向链表---遍历函数的封装

cs 复制代码
//修改
int change_link(Link_t *plink, Data_type_t olddata, Data_type_t newdata)
{
    Node_t *ptmp = find_link(plink, olddata);
   if(ptmp != NULL)
   {
       ptmp->data = newdata;
       return 0;
   }
    return -1;
}

(8)单向链表---删除函数的封装(删除前需判断是不是空结点)

cs 复制代码
/*是不是空结点*/
int is_empty_link(Link_t *plink)
{
    return NULL == plink->phead;
}

//删除
int delete_link_head(Link_t *plink)
{
    if(is_empty_link(plink))
    {
        return -1;
    }
    Node_t *ptmp;
    ptmp = plink->phead;
    plink->phead = ptmp->pnext;
    free(ptmp);

    plink->clen--;
    return 0;
}

(9) 上述代码在封装函数框需包含以下三种头文件,其中"link.h"是自己命名的声明文件,在后续内容中说明

cs 复制代码
#include<stdio.h>
#include<stdlib.h>
#include"link.h"
2)单向链表的函数声明
cs 复制代码
#ifndef _LINK_H
#define _LINK_H

/*链表存储的数据的数据类型*/
typedef int Data_type_t;

extern Link_t *create_link();
extern int insert_link_head(Link_t *plink, Data_type_t data);
extern void link_for_each(Link_t *plink);
extern Node_t *find_link(Link_t *plink, Data_type_t mydata);
extern int change_link(Link_t *plink, Data_type_t olddata, Data_type_t newdata);
extern int delete_link_head(Link_t *plink);

#endif
3)单向链表的上述函数在主函数中的运行格式
cs 复制代码
#include<stdio.h>
#include"link.h"

int main(int argc, const char *argv[])
{
    Node_t *ret = NULL;
    Link_t *plink = create_link();
    if(NULL == plink)
    {
        return -1;
    }
    insert_link_head(plink, 1);
    insert_link_head(plink, 2);
    insert_link_head(plink, 3);
    insert_link_head(plink, 4);
    insert_link_head(plink, 5);
    link_for_each(plink);
    
    ret = find_link(plink, 4);
    if(ret == NULL)
    {
        printf("not found\n");
    }
    else
    {
        printf("found %d\n", ret->data);
    }
    change_link(plink, 4, 15);
    link_for_each(plink);

    delete_link_head(plink); 
    link_for_each(plink);
    return 0;
}

【END】

相关推荐
疋瓞11 小时前
C++_STL和数据结构《1》_STL、STL_迭代器、c++中的模版、STL_vecto、列表初始化、三个算法、链表
数据结构·c++·算法
JJJJ_iii11 小时前
【左程云算法09】栈的入门题目-最小栈
java·开发语言·数据结构·算法·时间复杂度
三体世界11 小时前
测试用例全解析:从入门到精通(1)
linux·c语言·c++·python·功能测试·测试用例·测试覆盖率
Bear on Toilet11 小时前
继承类模板:函数未在模板定义上下文中声明,只能通过实例化上下文中参数相关的查找找到
开发语言·javascript·c++·算法·继承
金融小师妹11 小时前
多因子AI回归揭示通胀-就业背离,黄金价格稳态区间的时序建模
大数据·人工智能·算法
程序员东岸11 小时前
C语言入门指南:字符函数和字符串函数
c语言·笔记·学习·程序人生·算法
小猪咪piggy12 小时前
【算法】day2 双指针+滑动窗口
数据结构·算法·leetcode
max50060012 小时前
OpenSTL PredRNNv2 模型复现与自定义数据集训练
开发语言·人工智能·python·深度学习·算法
budingxiaomoli12 小时前
AVL树知识总结
数据结构·算法
jz-炸芯片的zero12 小时前
【Zephyr电源与功耗专题】14_BMS电池管理算法(三重验证机制实现高精度电量估算)
单片机·物联网·算法·zephyr·bms电源管理算法