【数据结构(初稿)】数据结构绪论及总体概述

halo~我是bay_Tong桐小白
本文内容是桐小白个人对所学知识进行的总结和分享,知识点会不定期进行编辑更新和完善,了解最近更新内容可参看更新日志,欢迎各位大神留言、指点

【更新日志】

最近更新:

  • 更新内容——修改 数据结构、抽象数据类型、算法与时空复杂度等概念(2021.10.20)
  • 持续更新中……

综述

数据结构

概念: 计算机存储、组织数据的方式

不同的数据结构具有各自对应的适用场景,旨在降低各种算法计算的时间与空间复杂度,达到最佳的任务执行效率

三要素: 数据的逻辑结构、数据的存储结构、数据的运算集合,三者缺一不可

  • 逻辑结构:数据元素之间的逻辑(即前趋/后继等)对应关系
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 存储结构(也称物理结构):逻辑结构在计算机中的存储映像,即数据元素之间的关系在计算机中的具体存储实现
  • 运算集合:对数据的具体表示以及相关运算操作的实现(如数据的增、删、改等)

基本分类

在这里插入图片描述

线性数据结构:非空集;仅有一个开始和一个终端;所有结点都最多只有一个直接前驱和一个直接后继。【简单说即逻辑关系上一对一】

非线性数据结构:非空集;每个结点可能有多个直接前驱或多个直接后继。【简单说即逻辑关系上一对多或多对多】

抽象数据类型

定义了一组数据对象、数据对象中各元素间的结构关系以及处理操作,通常指用以表示应用问题的数据模型,它在使用时不关心内部结构如何变化,不会影响其外部使用,是描述数据结构的一种理论工具,目的是独立于程序的实现细节来理解数据结构的特性

抽象数据类型包括数据对象、数据元素间的结构关系、操作三部分

算法与时空复杂度

算法:用来描述为解决特定问题而规定的一系列操作

算法的特性:有限性、确定性、可行性、输入、输出

算法的设计要求:正确性、可读性、健壮性(鲁棒性)、高效率和低存储

算法的时间复杂度:通常以算法中基本操作重复执行的频度作为度量标准,是问题规模n的函数

算法的空间复杂度:算法所耗费的存储空间的数量级,是问题规模n的函数。若算法执行时所需要的辅助空间相对于输入数据量而言是一个常数,则称这个算法为原地工作,辅助空间为O(1)

常见线性数据结构

数组

数组:相同类型的元素存储于连续内存空间的数据结构,可通过数组下标随机存取,数组大小固定
在这里插入图片描述

可变数组:基于数组和扩容机制实现,相比普通数组更加灵活。常用操作有:访问元素、添加元素、删除元素

//C
int array[1] = {0};
//添加元素并扩充数组大小
array = (int*)realloc(array,sizof(int)*5);
array[1] = 10;
/* realloc()函数语法:
指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)
对于新申请的数组大小,如果新的大于原内存大小,则新分配部分不会被初始化;如果新的大小小于原内存大小,可能会导致数据丢失
头文件:#include <stdlib.h> 有些编译器需要#include <malloc.h>
*/
//C++
vector<int> array;
//向尾部添加元素
array.push_back(10);

链表

链表:以结点为单位,每个数据元素除存储自身信息外还需存储它的直接前驱或直接后继的地址信息
在这里插入图片描述

在这里插入图片描述

//C
struct ListNode {
    int data;        // 结点数据
    ListNode* next; // 后继结点地址
};

struct ListNode* n1 = (struct ListNode*)calloc(1,sizeof(struct ListNode));
struct ListNode* n2 = (struct ListNode*)calloc(1,sizeof(struct ListNode));
struct ListNode* n3 = (struct ListNode*)calloc(1,sizeof(struct ListNode));
n1->data = 1;	n1->next = n2;
n2->data = 10;	n2->next = n3;
n3->data = 100;	n3->next = NULL;
//C++
struct ListNode {
    int data;        // 结点数据
    ListNode* next; // 后继结点地址
    ListNode(int x) : data(x) , next(NULL) {} //构造函数
};

ListNode* n1 = new ListNode(1);
ListNode* n2 = new ListNode(10);
ListNode* n3 = new ListNode(100);
n1->next = n2;	n2->next = n3;

【数组与链表详细知识内容可见本栏文章《线性表总结——基本知识要点汇总》

栈:只在一端(栈顶)做插入删除操作(称为入栈与出栈)的数据结构,具有先进后出【FILO】,后进先出【LIFO】的特点。可以由数组或链表实现
在这里插入图片描述

//C++
stack<char> s;
s.push('A');	s.push('B');	s.push('C');
s.pop();

队列

队列:只在一端(队尾)插入在另一端(队头)删除(称为入队与出队)的数据结构,具有先进先出【FIFO】,后进后出【LILO】的特点。可以由数组或链表实现
在这里插入图片描述

//C++
queue<int> q;
q.push(0);	q.push(1);	q.push(2);	q.push(3);	q.push(4);	q.push(5);
q.pop();

【栈与队列详细知识内容可见本栏文章《栈和队列总结——基本知识要点汇总》

常见非线性数据结构

常用的树型结构为二叉树,每个结点包含结点值、左孩子结点地址、右孩子结点地址
在这里插入图片描述

//C
struct TreeNode {
    char data;         // 结点值
    TreeNode* left;  // 左孩子结点
    TreeNode* right; // 右孩子结点
};

struct TreeNode* n1 = (struct TreeNode*)calloc(1, sizeof(struct TreeNode));
struct TreeNode* n2 = (struct TreeNode*)calloc(1, sizeof(struct TreeNode));
struct TreeNode* n3 = (struct TreeNode*)calloc(1, sizeof(struct TreeNode));
struct TreeNode* n4 = (struct TreeNode*)calloc(1, sizeof(struct TreeNode));
struct TreeNode* n5 = (struct TreeNode*)calloc(1, sizeof(struct TreeNode));
n1->data = 'A';	n1->left = n2;	n1->right = n3;
n2->data = 'B';	n2->left = n4;  n2->right = n5;
n3->data = 'C';	n3->left = NULL; n3->right = NULL;
n4->data = 'D';	n4->left = NULL; n4->right = NULL;
n5->data = 'E';	n5->left = NULL; n5->right = NULL;
//C++
struct TreeNode {
    char data;         // 节点值
    TreeNode* left;  // 左子节点
    TreeNode* right; // 右子节点
    TreeNode(int x) : data(x), left(NULL), right(NULL) {}//构造函数
};

TreeNode* n1 = new TreeNode('A');
TreeNode* n2 = new TreeNode('B');
TreeNode* n3 = new TreeNode('C');
TreeNode* n4 = new TreeNode('D');
TreeNode* n5 = new TreeNode('E');
n1->left = n2;  n1->right = n3;
n2->left = n4;  n2->right = n5;

【树型结构详细知识内容可见本栏文章《树和二叉树总结——基本知识要点汇总》

堆:一种基于完全二叉树的数据结构,可使用数组实现。堆分为大顶堆和小顶堆,大(小)顶堆:任意节点的值不大于(小于)其父节点的值

以 leetcode 《图解算法数据结构》中的例子为例:

如下图所示,为包含 1, 4, 2, 6, 8 元素的小顶堆。将堆(完全二叉树)中的结点按层编号,即可映射到右边的数组存储形式
在这里插入图片描述

//C++
// 初始化小顶堆
priority_queue<int, vector<int>, greater<int>> heap;

// 元素入堆
heap.push(1);
heap.push(4);
heap.push(2);
heap.push(6);
heap.push(8);

// 元素出堆(从小到大)
heap.pop(); // -> 1
heap.pop(); // -> 2
heap.pop(); // -> 4
heap.pop(); // -> 6
heap.pop(); // -> 8

作者:Krahets
链接:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/50e446/
来源:力扣(LeetCode)

散列表

散列表:通过利用 Hash 函数将指定的键(key)映射至对应的值(value),以实现高效的元素查找

以 leetcode 《图解算法数据结构》中的例子为例:

设想一个简单场景:小力、小特、小扣的学号分别为10001、10002、10003;现需求从「姓名」查找「学号」
可通过建立姓名为 key ,学号为 value 的散列表实现此需求
在这里插入图片描述

作者:Krahets
链接:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/50e446/
来源:力扣(LeetCode)

图:由节点(顶点)和边组成,每条边连接一对顶点
在这里插入图片描述
邻接矩阵表示法:二维数组来表示,如G[ i ][ j ]表示 i 到 j 的一条边,无权图中若有边则G[ i ][ j ]的值为1否则为0,有权图中若有边则该值可以是边的权重,若无边则为无穷大,以一个很大的数来表示
在这里插入图片描述

//C++
int vertices[5] = { 0, 1, 2, 3, 4 };
int edges[5][5] = { {0, 1, 0, 1, 0},
                    {1, 0, 1, 0, 1},
                    {0, 1, 0, 1, 1},
                    {1, 0, 1, 0, 0},
                    {0, 1, 1, 0, 0} };

邻接表表示法:用一个数组存储图中所有顶点,每一个顶点(数组单元)有一个单链表,存储所有和它关联的边

在这里插入图片描述
【图结构详细知识内容可见本栏文章《图的总结——基本知识要点汇总》

持续更新中……
我是桐小白,一个摸爬滚打的计算机小白

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值