软考中级复习篇章:数据结构部分的复习
软考中级快速通过篇章:数据结构部分的复习
一、引言
在软考中级的备考过程中,数据结构是极为重要的一个部分。它不仅是计算机科学的基础,也是软考中考查的重点知识领域。扎实掌握数据结构相关内容,对于顺利通过软考中级考试起着关键作用。本文将对数据结构部分的核心知识点进行全面总结,并配以简单的习题练习,帮助大家快速高效地复习这一板块,为软考中级考试做好充分准备。
二、数据结构基础概念
(一)数据结构的定义
数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。它主要研究数据的逻辑结构、存储结构以及在这些结构上定义的运算。
-
逻辑结构:描述数据元素之间的逻辑关系,如线性结构(线性表、栈、队列等)、非线性结构(树、图等)。
-
存储结构:数据在计算机中的存储方式,常见的有顺序存储、链式存储、索引存储和散列存储。
(二)数据类型
-
原子类型:其值不可再分的数据类型,如整型、实型、字符型等。
-
结构类型:由若干个数据项组成,其值可以再分解为若干个数据项,例如数组、结构体等。
三、线性表
(一)线性表的定义与特点
线性表是具有相同数据类型的 n 个数据元素的有限序列(n≥0),记为 (a1, a2, …, an)。它具有以下特点:
-
有且仅有一个第一个元素和最后一个元素。
-
除第一个元素外,每个元素有且仅有一个直接前驱;除最后一个元素外,每个元素有且仅有一个直接后继。
(二)顺序表
-
定义:用一组地址连续的存储单元依次存储线性表中的数据元素,这种存储结构的线性表称为顺序表。
-
优点:可以随机存取表中任一元素,存储密度高。
-
缺点:插入和删除操作需要移动大量元素,效率较低。
例如,在一个顺序表中插入元素的代码实现(以 C 语言为例):
#include <stdio.h>
#define MAXSIZE 100 typedef struct { int data[MAXSIZE]; int length;
} SqList; // 在顺序表L的第i个位置插入元素e
int ListInsert(SqList *L, int i, int e) { int j; if (i < 1 || i > L->length + 1) return 0; if (L->length >= MAXSIZE) return 0; for (j = L->length; j >= i; j--) L->data[j] = L->data[j - 1]; L->data[i - 1] = e; L->length++; return 1;
}
(三)链表
-
单链表:每个节点除了存放数据元素外,还需要存放一个指向其后继节点的指针。
-
双链表:在单链表的基础上,每个节点增加一个指向其前驱节点的指针,使得链表可以双向遍历。
-
循环链表:链表的最后一个节点的指针指向头节点,形成一个环。
下面是单链表插入节点的代码示例(以 C 语言为例):
#include <stdio.h>
#include <stdlib.h> typedef struct LNode { int data; struct LNode *next;
} LNode, *LinkList; // 在单链表L中第i个位置插入元素e
int ListInsert(LinkList *L, int i, int e) { int j = 1; LinkList p = *L, s; if (i == 1) { s = (LinkList)malloc(sizeof(LNode)); s->data = e; s->next = p; *L = s; return 1; } while (p && j < i - 1) { p = p->next; j++; } if (!p || j > i - 1) return 0; s = (LinkList)malloc(sizeof(LNode)); s->data = e; s->next = p->next; p->next = s; return 1;
}
四、栈和队列
(一)栈
-
定义:是一种只允许在一端进行插入和删除操作的线性表,按照后进先出(LIFO, Last In First Out)的原则组织数据。
-
栈的操作:初始化、入栈、出栈、取栈顶元素、判断栈是否为空等。
-
应用场景:表达式求值、括号匹配、函数调用等。
以下是一个简单的栈操作的代码实现(以 C 语言为例):
#include <stdio.h>
#include <stdlib.h> typedef struct Stack { int *data; int top; int size;
} Stack; // 初始化栈
Stack* initStack(int size) { Stack *s = (Stack*)malloc(sizeof(Stack)); s->data = (int*)malloc(size * sizeof(int)); s->top = -1; s->size = size; return s;
} // 判断栈是否为空
int isEmpty(Stack *s) { return s->top == -1;
} // 入栈
int push(Stack *s, int e) { if (s->top == s->size - 1) return 0; s->data[++(s->top)] = e; return 1;
} // 出栈
int pop(Stack *s, int *e) { if (isEmpty(s)) return 0; *e = s->data[(s->top)--]; return 1;
} // 取栈顶元素
int getTop(Stack *s, int *e) { if (isEmpty(s)) return 0; *e = s->data[s->top]; return 1;
}
(二)队列
-
定义:是一种只允许在一端进行插入,而在另一端进行删除操作的线性表,按照先进先出(FIFO, First In First Out)的原则组织数据。
-
队列的操作:初始化、入队、出队、取队头元素、判断队列是否为空等。
-
应用场景:广度优先搜索、打印任务排队等。
以循环队列为例,其代码实现如下(以 C 语言为例):
#include <stdio.h>
#include <stdlib.h> typedef struct { int *data; int front; int rear; int size;
} SqQueue; // 初始化队列
SqQueue* initQueue(int size) { SqQueue *q = (SqQueue*)malloc(sizeof(SqQueue)); q->data = (int*)malloc(size * sizeof(int)); q->front = q->rear = 0; q->size = size; return q;
} // 判断队列是否为空
int isEmpty(SqQueue *q) { return q->front == q->rear;
} // 入队
int enQueue(SqQueue *q, int e) { if ((q->rear + 1) % q->size == q->front) return 0; q->data[q->rear] = e; q->rear = (q->rear + 1) % q->size; return 1;
} // 出队
int deQueue(SqQueue *q, int *e) { if (isEmpty(q)) return 0; *e = q->data[q->front]; q->front = (q->front + 1) % q->size; return 1;
} // 取队头元素
int getFront(SqQueue *q, int *e) { if (isEmpty(q)) return 0; *e = q->data[q->front]; return 1;
}
五、串
(一)串的定义与存储
串是由零个或多个字符组成的有限序列,又称为字符串。串的存储方式有顺序存储和链式存储。
-
顺序存储:用一组地址连续的存储单元存储串中的字符序列。
-
链式存储:用链表存储串中的字符序列,每个节点可以存储一个或多个字符。
(二)串的基本操作
求串长、串连接、子串定位、串比较等。
例如,求串长的代码实现(以 C 语言为例):
#include <stdio.h> int StrLength(char *s) { int len = 0; while (s[len]!= '\0') len++; return len;
}
六、数组和广义表
(一)数组
-
定义:数组是由 n 个相同类型的数据元素构成的有限序列,每个数据元素称为数组元素,每个元素在 n 个线性关系中的序号称为该元素的下标,下标的取值范围称为数组的维界。
-
数组的存储:对于一维数组,按顺序存储;对于多维数组,有行优先存储和列优先存储两种方式。
例如,二维数组行优先存储的地址计算公式:对于二维数组 A [m][n],假设每个元素占 L 个存储单元,起始地址为 LOC (A [0][0]),则元素 A [i][j] 的存储地址为 LOC (A [i][j]) = LOC (A [0][0]) + (i * n + j) * L。
(二)广义表
-
定义:广义表是线性表的推广,是由零个或多个单元素或子表所组成的有限序列。
-
特点:广义表可以是递归的,即广义表可以是其自身的子表;广义表的元素可以是不同类型的。
例如,广义表 LS = (a, (b, (c, d)), e),其中 a、e 是单元素,(b, (c, d)) 是子表。
七、树和二叉树
(一)树的基本概念
-
树的定义:树是 n(n≥0)个节点的有限集合。当 n = 0 时,称为空树;在任意一棵非空树中,有且仅有一个特定的称为根的节点,当 n > 1 时,其余节点可分为 m(m > 0)个互不相交的有限集 T1, T2, …, Tm,其中每个集合本身又是一棵树,并且称为根的子树。
-
树的基本术语:节点的度、树的度、叶子节点、分支节点、层次、深度等。
(二)二叉树
-
二叉树的定义:二叉树是 n(n≥0)个节点的有限集合,该集合或者为空集(空二叉树),或者由一个根节点和两棵互不相交的、分别称为根节点的左子树和右子树的二叉树组成。
-
二叉树的性质:
-
- 在二叉树的第 i 层上至多有 2^(i - 1) 个节点(i≥1)。
-
- 深度为 k 的二叉树至多有 2^k - 1 个节点(k≥1)。
-
- 对任何一棵二叉树 T,如果其终端节点数为 n0,度为 2 的节点数为 n2,则 n0 = n2 + 1。
-
特殊二叉树:满二叉树、完全二叉树。
(三)二叉树的遍历
-
先序遍历:先访问根节点,再先序遍历左子树,最后先序遍历右子树。
-
中序遍历:先中序遍历左子树,再访问根节点,最后中序遍历右子树。
-
后序遍历:先后序遍历左子树,再后序遍历右子树,最后访问根节点。
-
层序遍历:从根节点开始,逐层从左到右访问节点。
以下是二叉树先序遍历的递归代码实现(以 C 语言为例):
#include <stdio.h>
#include <stdlib.h> typedef struct BiTNode { char data; struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree; // 先序遍历二叉树
void PreOrderTraverse(BiTree T) { if (T) { printf("%c ", T->data); PreOrderTraverse(T->lchild); PreOrderTraverse(T->rchild); }
}
(四)线索二叉树
-
线索二叉树的定义:为了能方便地找到二叉树中节点的前驱和后继,引入线索二叉树的概念。对二叉树的节点进行某种遍历,使其变为一个有序的线性序列,在这个序列中,每个节点有且仅有一个前驱和一个后继。对于没有前驱或后继的节点,用线索(指针)指向其前驱或后继。
-
线索二叉树的构造:通过遍历二叉树,在遍历过程中修改空指针,使其指向该节点的前驱或后继。
(五)树和森林
-
树与二叉树的转换:可以将树转换为二叉树,以便利用二叉树的算法来处理树的问题。转换方法是:树中每个节点的第一个孩子作为其在二叉树中的左孩子,该节点的下一个兄弟作为其在二叉树中的右孩子。
-
森林与二叉树的转换:先将森林中的每棵树转换为二叉树,然后将第一棵二叉树的根作为整个二叉树的根,依次将后一棵二叉树作为前一棵二叉树的右子树。
(六)哈夫曼树
-
哈夫曼树的定义:给定 n 个权值作为 n 个叶子节点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。
-
哈夫曼树的构造:根据给定的 n 个权值,构造 n 棵只有一个节点的二叉树,组成森林 F;在 F 中选取两棵根节点权值最小的树作为左右子树构造一棵新的二叉树,其根节点的权值为左右子树根节点权值之和;在 F 中删除这两棵树,并将新的二叉树加入 F;重复上述步骤,直到 F 中只剩下一棵树,这棵树就是哈夫曼树。
八、图
(一)图的基本概念
-
图的定义:图是由顶点集 V 和边集 E 组成,记为 G = (V, E),其中 V (G) 表示图 G 中顶点的有限非空集;E (G) 表示图 G 中顶点之间的关系(边)集合。
-
图的基本术语:有向图、无向图、弧、顶点的度、入度、出度、路径、回路等。
(二)图的存储结构
-
邻接矩阵:用一个二维数组来表示图中顶点之间的邻接关系。对于无向图,邻接矩阵是对称矩阵;对于有向图,邻接矩阵不一定对称。
-
邻接表:对图中的每个顶点建立一个单链表,链表中的节点表示与该顶点相邻接的顶点。
(三)图的遍历
-
深度优先搜索(DFS):类似于树的先序遍历,从图中某个顶点 v 出发,访问此顶点,然后从 v 的未被访问的邻接点出发深度优先遍历图,直至图中所有和 v 有路径相通的顶点都被访问到。
-
广度优先搜索(BFS):类似于树的层序遍历,从图中某顶点 v 出发,在访问了 v 之后依次访问 v 的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使 “先被访问的顶点的邻接点” 先于 “后被访问的顶点的邻接点” 被访问,直至图中所有已被访问的顶点的邻接点都被访问到。
(四)最小生成树
-
定义:对于一个带权连通无向图 G=(V, E),生成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。设 R 为 G 的所有生成树的集合,若 T 为 R 中权值之和最小的生成树,则 T 称为 G 的最小生成树。
-
构造算法:普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法。
(五)最短路径
-
单源最短路径:从一个源点到其余各顶点的最短路径。常用的算法有迪杰斯特拉(Dijkstra)算法。
-
每对顶点之间的最短路径:计算图中每对顶点之间的最短路径。常用的算法有弗洛伊德(Floyd)算法。
第二篇
1. 数据结构概述
1.1 数据结构的基本概念
数据结构是计算机存储、组织数据的方式,它涉及到数据的逻辑结构、存储结构以及数据的运算。数据结构的选择直接影响程序的效率和性能。
详细分析:
- 逻辑结构:描述数据元素之间的逻辑关系,如线性关系、树形关系、图形关系等。
- 存储结构:描述数据在计算机中的存储方式,如顺序存储、链式存储、索引存储等。
- 数据运算:包括插入、删除、查找、排序等操作。
示例:
- 逻辑结构:数组是一种线性结构,元素之间是一对一的关系。
- 存储结构:数组通常采用顺序存储,元素在内存中是连续存放的。
- 数据运算:数组的查找操作时间复杂度为 O ( 1 ) O(1) O(1),插入和删除操作时间复杂度为 O ( n ) O(n) O(n)。
1.2 数据结构的分类
数据结构可以分为线性结构、非线性结构和集合结构。
详细分析:
- 线性结构:元素之间存在一对一的线性关系,如数组、链表、栈、队列。
- 非线性结构:元素之间存在一对多或多对多的关系,如树、图。
- 集合结构:元素之间没有明显的逻辑关系,如哈希表、集合。
示例:
- 线性结构:链表中的每个节点只有一个前驱和一个后继。
- 非线性结构:树中的每个节点可以有多个子节点。
- 集合结构:哈希表中的元素通过哈希函数映射到不同的位置。
1.3 数据结构的应用
数据结构广泛应用于数据库、操作系统、编译器设计、网络通信等领域。
详细分析:
- 数据库:B树、哈希表用于索引和数据存储。
- 操作系统:队列用于任务调度,栈用于函数调用。
- 编译器设计:语法树用于语法分析。
- 网络通信:图用于路由算法。
示例:
- 数据库:MySQL使用B+树作为索引结构,提高查询效率。
- 操作系统:Linux内核使用红黑树管理内存块。
2. 线性结构
2.1 数组
数组是一种线性数据结构,它用一组连续的内存空间来存储相同类型的数据。
详细分析:
- 定义:数组是一种静态数据结构,大小固定。
- 操作:
- 插入:在指定位置插入元素,需要移动后续元素。
- 删除:删除指定位置的元素,需要移动后续元素。
- 查找:通过索引直接访问元素。
- 时间复杂度:
- 查找: O ( 1 ) O(1) O(1)
- 插入/删除: O ( n ) O(n) O(n)
示例:
# 数组的插入操作
arr = [1, 2, 3, 4, 5]
arr.insert(2, 10) # 在索引2处插入10
print(arr) # 输出: [1, 2, 10, 3, 4, 5]
2.2 链表
链表是一种动态数据结构,它通过指针将一组零散的内存块串联起来。
详细分析:
- 定义:链表是一种动态数据结构,大小可以动态调整。
- 类型:
- 单链表:每个节点只有一个指针指向下一个节点。
- 双链表:每个节点有两个指针,分别指向前一个节点和后一个节点。
- 循环链表:尾节点的指针指向头节点,形成一个环。
- 操作:
- 插入:在指定位置插入节点,只需修改指针。
- 删除:删除指定位置的节点,只需修改指针。
- 查找:需要从头节点开始遍历。
- 时间复杂度:
- 查找: O ( n ) O(n) O(n)
- 插入/删除: O ( 1 ) O(1) O(1)
示例:
# 单链表的插入操作
class Node:def __init__(self, data):self.data = dataself.next = Noneclass LinkedList:def __init__(self):self.head = Nonedef insert(self, data, position):new_node = Node(data)if position == 0:new_node.next = self.headself.head = new_nodeelse:current = self.headfor _ in range(position - 1):if current is None:raise IndexError("Position out of range")current = current.nextnew_node.next = current.nextcurrent.next = new_node# 使用示例
ll = LinkedList()
ll.insert(1, 0)
ll.insert(2, 1)
ll.insert(3, 1)
2.3 栈
栈是一种后进先出(LIFO)的数据结构。
详细分析:
- 定义:栈是一种受限的线性结构,只允许在一端进行插入和删除操作。
- 操作:
- 入栈(push):将元素压入栈顶。
- 出栈(pop):将栈顶元素弹出。
- 应用:
- 函数调用栈:用于保存函数调用的上下文。
- 表达式求值:用于中缀表达式转后缀表达式。
示例:
# 栈的实现
class Stack:def __init__(self):self.items = []def push(self, item):self.items.append(item)def pop(self):if not self.is_empty():return self.items.pop()raise IndexError("Pop from empty stack")def is_empty(self):return len(self.items) == 0# 使用示例
stack = Stack()
stack.push(1)
stack.push(2)
print(stack.pop()) # 输出: 2
2.4 队列
队列是一种先进先出(FIFO)的数据结构。
详细分析:
- 定义:队列是一种受限的线性结构,只允许在一端插入,在另一端删除。
- 类型:
- 普通队列:基本的FIFO队列。
- 循环队列:通过循环利用数组空间,解决普通队列的空间浪费问题。
- 优先队列:元素按优先级出队,通常使用堆实现。
- 操作:
- 入队(enqueue):将元素插入队尾。
- 出队(dequeue):将队头元素删除。
- 应用:
- 任务调度:操作系统中的任务调度队列。
- 缓冲区管理:网络通信中的数据传输缓冲区。
示例:
# 队列的实现
from collections import dequeclass Queue:def __init__(self):self.items = deque()def enqueue(self, item):self.items.append(item)def dequeue(self):if not self.is_empty():return self.items.popleft()raise IndexError("Dequeue from empty queue")def is_empty(self):return len(self.items) == 0# 使用示例
queue = Queue()
queue.enqueue(1)
queue.enqueue(2)
print(queue.dequeue()) # 输出: 1
3. 非线性结构
3.1 树
树是一种层次结构,由节点和边组成。
详细分析:
- 定义:树是一种非线性结构,每个节点可以有多个子节点。
- 类型:
- 二叉树:每个节点最多有两个子节点。
- 二叉搜索树:左子树的所有节点值小于根节点,右子树的所有节点值大于根节点。
- 平衡二叉树:左右子树的高度差不超过1,如AVL树、红黑树。
- 遍历方式:
- 前序遍历:根节点 -> 左子树 -> 右子树。
- 中序遍历:左子树 -> 根节点 -> 右子树。
- 后序遍历:左子树 -> 右子树 -> 根节点。
- 层次遍历:按层次从上到下,从左到右遍历。
- 应用:
- 文件系统:目录树结构。
- 数据库索引:B树、B+树用于数据库索引。
示例:
# 二叉树的遍历
class TreeNode:def __init__(self, data):self.data = dataself.left = Noneself.right = Nonedef pre_order_traversal(root):if root:print(root.data, end=" ")pre_order_traversal(root.left)pre_order_traversal(root.right)# 使用示例
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
pre_order_traversal(root) # 输出: 1 2 3
3.2 图
图是由节点和边组成的非线性结构。
详细分析:
- 定义:图是一种复杂的非线性结构,节点之间可以有任意关系。
- 类型:
- 有向图:边有方向。
- 无向图:边没有方向。
- 加权图:边有权重。
- 遍历方式:
- 深度优先搜索(DFS):沿着一条路径深入,直到不能再深入为止,然后回溯。
- 广度优先搜索(BFS):按层次遍历,先访问离起点最近的节点。
- 应用:
- 社交网络:用户之间的关系图。
- 路径规划:地图导航中的最短路径算法。
示例:
# 图的深度优先搜索
from collections import defaultdictclass Graph:def __init__(self):self.graph = defaultdict(list)def add_edge(self, u, v):self.graph[u].append(v)def dfs(self, v, visited):visited.add(v)print(v, end=" ")for neighbor in self.graph[v]:if neighbor not in visited:self.dfs(neighbor, visited)# 使用示例
g = Graph()
g.add_edge(0, 1)
g.add_edge(0, 2)
g.add_edge(1, 2)
g.add_edge(2, 0)
g.add_edge(2, 3)
g.add_edge(3, 3)
g.dfs(2, set()) # 输出: 2 0 1 3
4. 集合结构
4.1 哈希表
哈希表是一种通过哈希函数将键映射到值的数据结构。
详细分析:
- 定义:哈希表通过哈希函数将键映射到数组的索引,从而实现快速查找。
- 操作:
- 插入:通过哈希函数计算索引,将键值对存储在数组中。
- 删除:通过哈希函数计算索引,删除对应的键值对。
- 查找:通过哈希函数计算索引,直接访问对应的值。
- 时间复杂度:
- 平均 O ( 1 ) O(1) O(1),最坏 O ( n ) O(n) O(n)(哈希冲突时)。
- 应用:
- 字典:Python中的
dict
类型就是基于哈希表实现的。 - 缓存:缓存系统中常用哈希表存储键值对。
- 字典:Python中的
示例:
# 哈希表的实现
class HashTable:def __init__(self, size):self.size = sizeself.table = [[] for _ in range(size)]def _hash(self, key):return hash(key) % self.sizedef insert(self, key, value):index = self._hash(key)for kvp in self.table[index]:if kvp[0] == key:kvp[1] = valuereturnself.table[index].append([key, value])def get(self, key):index = self._hash(key)for kvp in self.table[index]:if kvp[0] == key:return kvp[1]raise KeyError(f"Key {key} not found")# 使用示例
ht = HashTable(10)
ht.insert("name", "Alice")
print(ht.get("name")) # 输出: Alice
4.2 集合
集合是一种不包含重复元素的数据结构。
详细分析:
- 定义:集合是一种无序的数据结构,元素之间没有重复。
- 操作:
- 并集:两个集合的所有元素。
- 交集:两个集合共有的元素。
- 差集:一个集合有而另一个集合没有的元素。
- 应用:
- 数据去重:去除列表中的重复元素。
- 集合运算:如并集、交集、差集等。
示例:
# 集合的操作
set1 = {1, 2, 3}
set2 = {3, 4, 5}
print(set1.union(set2)) # 输出: {1, 2, 3, 4, 5}
print(set1.intersection(set2)) # 输出: {3}
print(set1.difference(set2)) # 输出: {1, 2}
5. 习题练习
5.1 数组习题
-
找出数组中的最大值和最小值:
def find_max_min(arr):return max(arr), min(arr)
-
将数组中的元素逆序排列:
def reverse_array(arr):return arr[::-1]
5.2 链表习题
-
实现单链表的插入和删除操作:
class Node:def __init__(self, data):self.data = dataself.next = Noneclass LinkedList:def __init__(self):self.head = Nonedef insert(self, data, position):new_node = Node(data)if position == 0:new_node.next = self.headself.head = new_nodeelse:current = self.headfor _ in range(position - 1):if current is None:raise IndexError("Position out of range")current = current.nextnew_node.next = current.nextcurrent.next = new_nodedef delete(self, position):if position == 0:self.head = self.head.nextelse:current = self.headfor _ in range(position - 1):if current is None:raise IndexError("Position out of range")current = current.nextcurrent.next = current.next.next
-
判断链表是否有环:
def has_cycle(head):slow = headfast = headwhile fast and fast.next:slow = slow.nextfast = fast.next.nextif slow == fast:return Truereturn False
5.3 栈和队列习题
-
使用栈实现一个简单的计算器:
def calculate(expression):stack = []for char in expression:if char.isdigit():stack.append(int(char))else:b = stack.pop()a = stack.pop()if char == '+':stack.append(a + b)elif char == '-':stack.append(a - b)elif char == '*':stack.append(a * b)elif char == '/':stack.append(a // b)return stack.pop()
-
使用队列实现一个任务调度系统:
from collections import dequeclass TaskScheduler:def __init__(self):self.queue = deque()def add_task(self, task):self.queue.append(task)def run_task(self):if self.queue:return self.queue.popleft()return None
5.4 树习题
-
实现二叉树的遍历算法:
def in_order_traversal(root):if root:in_order_traversal(root.left)print(root.data, end=" ")in_order_traversal(root.right)
-
判断二叉树是否为平衡二叉树:
def is_balanced(root):def check_height(node):if not node:return 0left_height = check_height(node.left)right_height = check_height(node.right)if abs(left_height - right_height) > 1:return -1return max(left_height, right_height) + 1return check_height(root) != -1
5.5 图习题
-
实现图的深度优先搜索(DFS)和广度优先搜索(BFS):
def bfs(graph, start):visited = set()queue = deque([start])while queue:vertex = queue.popleft()if vertex not in visited:print(vertex, end=" ")visited.add(vertex)queue.extend(graph[vertex] - visited)
-
找出图中的最短路径:
from collections import dequedef shortest_path(graph, start, end):queue = deque([(start, [start])])while queue:(vertex, path) = queue.popleft()for next_vertex in graph[vertex] - set(path):if next_vertex == end:return path + [next_vertex]else:queue.append((next_vertex, path + [next_vertex]))return None
5.6 哈希表习题
- 实现一个简单的哈希表,并处理冲突:
class HashTable:def __init__(self, size):self.size = sizeself.table = [[] for _ in range(size)]def _hash(self, key):return hash(key) % self.sizedef insert(self, key, value):index = self._hash(key)for kvp in self.table[index]:if kvp[0] == key:kvp[1] = valuereturnself.table[index].append([key, value])def get(self, key):index = self._hash(key)for kvp in self.table[index]:if kvp[0] == key:return kvp[1]raise KeyError(f"Key {key} not found")
第三篇
- 线性表
顺序表(数组)
定义:顺序表使用一段连续的内存空间来存储元素,每个元素通过下标来访问。
特点:
优点:
支持随机访问,查找效率高。
内存空间连续,利用率较高。
缺点:
插入和删除操作需要移动大量元素,效率较低。
固定大小,可能会浪费空间或出现空间不足的问题。
链表
定义:链表是一种由节点组成的数据结构,每个节点包含数据和一个指向下一个节点的指针。
特点:
优点:
动态分配内存,避免空间浪费。
插入和删除操作高效,不需要移动大量元素。
缺点:
查找操作需要遍历链表,效率低。
每个节点需要额外的存储空间来存储指针。
应用:
顺序表适用于需要频繁查找、但修改较少的场景。
链表适用于需要频繁插入和删除元素的场景。
3. 栈与队列
栈(Stack)
定义:栈是一种后进先出(LIFO)结构,元素只能从栈顶插入或删除。
常见操作:
push: 压栈,将元素添加到栈顶。
pop: 弹栈,从栈顶移除元素。
peek: 查看栈顶元素。
应用:
栈常用于处理递归问题、表达式求值、括号匹配等。
队列(Queue)
定义:队列是一种先进先出(FIFO)结构,元素只能从队尾插入,从队头删除。
常见操作:
enqueue: 入队,将元素添加到队尾。
dequeue: 出队,从队头移除元素。
front: 查看队头元素。
应用:
队列常用于任务调度、资源管理、广度优先搜索等。
4. 树与图
树
定义:树是一种层次结构的数据结构,节点之间存在一对多的关系。每个节点有一个父节点和多个子节点。
类型:
二叉树:每个节点最多有两个子节点。
平衡二叉树(AVL树、红黑树):自平衡二叉树,保证树的高度平衡,使查找、插入和删除的时间复杂度保持在O(logn)。
堆:完全二叉树的特例,用于实现优先队列。
应用:
树常用于存储有层级关系的数据,例如文件系统、数据库索引、表达式求值等。
图
定义:图是由顶点和边组成的集合,顶点代表数据,边表示数据之间的关系。
类型:
无向图:边没有方向。
有向图:边有方向。
带权图:边有权值。
应用:
图常用于社交网络、路径规划、网络流量分析等问题。
5. 常见算法
数据结构的学习不仅仅是掌握不同类型的数据存储方式,还要学习如何使用合适的算法来处理这些数据。常见的算法包括排序、查找和图算法。
排序算法
冒泡排序:比较相邻元素并交换,直到数组有序。时间复杂度O(n²)。
快速排序:基于分治法,选择一个基准元素,分割成小于基准和大于基准的两部分,递归处理。时间复杂度O(nlogn)。
归并排序:也基于分治法,将数组分割成更小的部分,再合并。时间复杂度O(nlogn)。
应用:
排序算法用于将无序数据排序,广泛应用于数据库、文件系统等。
查找算法
顺序查找:逐个元素比较,时间复杂度O(n)。
二分查找:在有序数组中,利用分治法不断缩小查找范围,时间复杂度O(logn)。
应用:
查找算法用于从数据集合中找到特定元素。
图算法
深度优先搜索(DFS):从一个顶点开始,沿着图的边进行深度搜索,直到遍历到所有可达节点。常用于图的遍历、拓扑排序等。
广度优先搜索(BFS):从一个顶点开始,沿着图的边进行广度搜索,直到遍历到所有可达节点。常用于最短路径算法、社交网络分析等。
6. 数据结构的应用
数据结构不仅仅是理论知识,它们广泛应用于各类实际问题的解决中。掌握如何选择合适的数据结构和算法能够大大提高程序的效率。常见的应用包括:
栈和队列:用于递归处理、括号匹配、任务调度、资源分配等。
树:用于数据库索引、文件系统、XML解析等。
图:用于网络拓扑、路径规划、社交网络分析等
相关文章:
软考中级复习篇章:数据结构部分的复习
软考中级快速通过篇章:数据结构部分的复习 一、引言 在软考中级的备考过程中,数据结构是极为重要的一个部分。它不仅是计算机科学的基础,也是软考中考查的重点知识领域。扎实掌握数据结构相关内容,对于顺利通过软考中级考试起着…...
【Vim Masterclass 笔记22】S09L40 + L41:同步练习11:Vim 的配置与 vimrc 文件的相关操作(含点评课内容)
文章目录 S09L40 Exercise 11 - Vim Settings and the Vimrc File1 训练目标2 操作指令2.1. 打开 vimrc-sample 文件2.2. 尝试各种选项与设置2.3. 将更改内容保存到 vimrc-sample 文件2.4. 将文件 vimrc-sample 的内容复制到寄存器2.5. 创建专属 vimrc 文件2.6. 对于 Mac、Linu…...
Spring Boot 整合 PageHelper 实现分页功能
在开发 Web 应用时,分页功能几乎是必不可少的。Spring Boot 提供了强大的功能来简化开发,而 PageHelper 则是一个优秀的 MyBatis 分页插件,可以极大地简化分页查询的代码。本文将介绍如何在 Spring Boot 项目中整合 PageHelper,并…...
Redis和MongoDB的区别
前言 在项目选型阶段,MongoDB被选中主要是基于其处理大规模数据集的能力,而当时并未深入探讨其他替代方案。此前,Redis被用于管理少量但访问频繁的热数据。目前,项目采用MongoDB存储百万级数据,预计未来数据量将增长至…...
Java基础(2)
博客:深入理解浮点型数据、计算机视觉信息存储与类型转换 四、浮点型数据 在编程语言中,浮点型数据主要包括float(单精度)和double(双精度)。计算机默认使用double类型存储小数,这会引发一些特…...
D3.js及实例应用
文章目录 D3.jsd3.js 应用实例图标展示点击选择拖拉拽应用 D3.js D3.js是一个功能强大的JavaScript库,除了图标展示,还能实现多种类型的交互效果: 数据可视化交互 动态更新图表:根据用户操作(如点击按钮、选择下拉菜…...
管理权限特权
管理权限 Oracle 用户权限分为两种类型: 系统权限:允许用户在数据库中执行特定的操作。 对象权限:允许用户访问和操作特定的对象。 系统权限 Oracle 数据库中有超过100种不同的系统权限。权限中的 “ANY” 关键字表示用户在任何模式&#x…...
基于海思soc的智能产品开发(视频的后续开发)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 前面我们讨论了camera,也讨论了屏幕驱动,这些都是基础的部分。关键是,我们拿到了这些视频数据之后,…...
为什么相关性不是因果关系?人工智能中的因果推理探秘
目录 一、背景 (一)聚焦当下人工智能 (二)基于关联框架的人工智能 (三)基于因果框架的人工智能 二、因果推理的基本理论 (一)因果推理基本范式:因果模型࿰…...
【QT】已解决:Qt4.11.0无法使用MSVC编译器问题
目录 一、背景 1.本机环境 2.问题描述 3.问题解决前后对比图 二、详细操作 1.下载项目二所需qt环境 2.解决思路 3.安装VS2017 4.安装MSVC调试器 5.打开qtCreator查看编译器 5.编译运行项目二 三、参考 一、背景 1.本机环境 windows11 qtCreator4.11.0 minGW 64位…...
python如何解析word文件格式(.docx)
python如何解析word文件格式(.docx) .docx文件遵从开源的“Office Open XML标准”,这意味着我们能用python的文本操作对它进行操作(实际上PPT和Excel也是)。而且这并不是重复造轮子,因为市面上操作.docx的…...
点云目标检测训练数据预处理---平面拟合与坐标转换(python实现)
在做centerpoint训练之前,需要先对点云数据进行标注,然后制作kittti数据集。不用nuScenes或者waymo数据集的理由也很简单,因为麻烦,没有kitti数据集直观。 kitti数据集的格式如下,可以看到数据集中只有航向角ÿ…...
Debezium日常分享系列之:对于从Oracle数据库进行快照的性能优化
Debezium日常分享系列之:对于从Oracle数据库进行快照的性能优化 源数据库Kafka Connect监控测试结果 源数据库 Oracle 19c,本地,CDB数据库主机的I/O带宽为6 GB/s,由此主机上运行的所有数据库共享临时表空间由42个文件组成&#x…...
logback日志自定义占位符
前言 在大型系统运维中,很大程度上是需要依赖日志的。在java大型web工程中,一般都会使用slf4jlogback这一个组合来实现日志的管理。 logback中很多现成的占位符可以可以直接使用,比如线程号【%t】、时间【%d】、日志等级【%p】,…...
【Red Hat8】:搭建FTP服务器
目录 一、匿名FTP访问 1、新建挂载文件 2、挂载 3、关闭防火墙 4、搭建yum源 5、安装VSFTPD 6、 打开配置文件 7、设置配置文件如下几个参数 8、重启vsftpd服务 9、进入图形化界面配置网络 10、查看IP地址 11、安装ftp服务 12、遇到拒绝连接 13、测试 二、本地…...
华为AI培训-NLP实验
中文分词、命名实体识别、语义词性标注、语句逻辑推理、文本摘要、机器翻译、文本情感分析、内容创作 1 实验介绍 1.1 实验背景 中文分词、命名实体识别、语义词性标注、语句逻辑推理是自然语言处理领域中的重要任务。中文分词是将连续的汉字序列切分成有意义的词语序列…...
goodreads书籍评论爬取NRC Emotion Lexicon分析
文章目录 目标网站数据获取评论情感分析对爬虫、逆向感兴趣的同学可以查看文章,一对一小班教学:https://blog.csdn.net/weixin_35770067/article/details/142514698 目标网站 https://www.goodreads.com/book/show/3656.The_Sea 就是针对一本书进行3000+评论抓取和情感分析…...
【vitePress】基于github快速添加评论功能(giscus)
一.添加评论插件 使用giscus来做vitepress 的评论模块,使用也非常的简单,具体可以参考:giscus 文档,首先安装giscus npm i giscus/vue 二.giscus操作 打开giscus 文档,如下图所示,填入你的 github 用户…...
论文笔记(六十二)Diffusion Reward Learning Rewards via Conditional Video Diffusion
Diffusion Reward Learning Rewards via Conditional Video Diffusion 文章概括摘要1 引言2 相关工作3 前言4 方法4.1 基于扩散模型的专家视频建模4.2 条件熵作为奖励4.3 训练细节 5 实验5.1 实验设置5.2 主要结果5.3 零样本奖励泛化5.4 真实机器人评估5.5 消融研究 6 结论 文章…...
电梯系统的UML文档07
从这个类中得到的类图,构划出了软件的大部分设计。 系统结构视图提供软件和整个系统结构最复杂的也是最优雅的描述。和通常的软件系统相比,在分布式嵌入系统中了解系统组件如何协同工作是非常重要的。毕竟,每个类图仅仅是一个系统的静态设计…...
【Python】综合案例--人生重开模拟器
1. 设置初始属性 在游戏中我们设定四个属性.: 颜值 (face) 体质 (strong) 智力 (iq) 家境 (home)我们约定每个属性的范围为 [1, 10], 并且总和不能超过 20. 如果玩家输入的初始属性不合理, 就提示输入有误, 重新输入. print("-----------------------------------------…...
vue+高德API搭建前端3D交通页面
1. 模板部分 (<template>) <template><div class"content"><div><div id"container"></div></div></div> </template> 功能:定义了组件的HTML结构。分析: div.content 是最…...
2024年博客之星主题创作|猫头虎分享AI技术洞察:2025年AI发展趋势前瞻与展望
2025年AI发展趋势前瞻:猫头虎深度解析未来科技与商业机遇 摘要 2024年,AI技术迎来爆发式增长,AIGC、智能体、AIRPA、AI搜索、推理模型等技术不断突破,AI应用场景持续扩展。2025年,AI将进入全新发展阶段,W…...
算法刷题笔记——图论篇
这里写目录标题 理论基础图的基本概念图的种类度 连通性连通图强连通图连通分量强连通分量 图的构造邻接矩阵邻接表 图的遍历方式 深度优先搜索理论基础dfs 与 bfs 区别dfs 搜索过程深搜三部曲所有可达路径广度优先搜索理论基础广搜的使用场景广搜的过程 岛屿数量孤岛的总面积沉…...
虚幻基础-1:cpu挑选(14600kf)
能帮到你的话,就给个赞吧 😘 文章目录 ue非常吃cpu拉满主频打开项目编写蓝图运行原因 时间长 关于压力测试 本文以14600kf为例,双12购入,7月份产。 ue非常吃cpu 经本人测试,ue是非常吃cpu的。 拉满主频 无论任何时间…...
IP地址:127.0.0.1
概述 首先,我们需要明确 127.0.0.1 地址的含义。在网络中,127.0.0.1 地址称为本地回环地址,是一种特殊的网络地址,用于让单独的计算机进行自我回路测试和通信。这个地址在 IP 协议中被定义为环回地址。 在网络设备中,…...
深度学习 | pytorch + torchvision + python 版本对应及环境安装
Hi,大家好,我是半亩花海。要让一个基于 torch 框架开发的深度学习模型正确运行起来,配置环境是个重要的问题,本文介绍了 pytorch、torchvision、torchaudio 及 python 的对应版本以及环境安装的相关流程。 目录 一、版本对应 二…...
学习ASP.NET Core的身份认证(基于JwtBearer的身份认证6)
重新创建WebApi项目,安装Microsoft.AspNetCore.Authentication.JwtBearer包,将之前JwtBearer测试项目中的初始化函数,jwt配置类、token生成类全部挪到项目中。 重新编写login函数,之前测试Cookie和Session认证时用的函数适合m…...
企业级流程架构设计思路-基于价值链的流程架构
获取更多企业流程资料 纸上得来终觉浅,绝知此事要躬行 一.企业流程分级规则定义 1.流程分类分级的总体原则 2.完整的流程体系需要体现出流程的分类分级 03.通用的流程分级方法 04.流程分级的标准 二.企业流程架构设计原则 1.流程架构设计原则 流程框架是流程体…...
深度学习 DAY2:Transformer(一部分)
前言 Transformer是一种用于自然语言处理(NLP)和其他序列到序列(sequence-to-sequence)任务的深度学习模型架构,它在2017年由Vaswani等人首次提出。Transformer架构引入了自注意力机制(self-attention mech…...
【2025】拥抱未来 砥砺前行
2024是怎样的一年 2024在历史画卷上是波澜壮阔的一年,人工智能的浪潮来临,涌现出无数国产大模型。 22年11月ChatGPT发布,它的出现如同在平静湖面上投下一颗巨石,激起了层层波澜,短短五天用户数就达到了100万࿰…...
精选100+套HTML可视化大屏模板源码素材
大屏数据可视化以大屏为主要展示载体的数据可视化设计。 “大面积、炫酷动效、丰富色彩”,大屏易在观感上给人留下震撼印象,便于营造某些独特氛围、打造仪式感。 原本看不见的数据可视化后,便能调动人的情绪、引发人的共鸣。 使用方法&…...
欧拉(Euler 22.03)安装ProxySQL
下载离线安装包 proxysql-2.0.8-1-centos7.x86_64.rpm 链接: https://pan.baidu.com/s/1R-SJiVUEu24oNnPFlm9wRw 提取码: sa2w离线安装proxysql yum localinstall -y proxysql-2.0.8-1-centos7.x86_64.rpm 启动proxysql并检查状态 systemctl start proxysql 启动proxysql syste…...
Electron实践继续
文章目录 前言一、知识储备前提二、开发工具集(一)代码编辑器之选(二)命令行工具运用(三)Git 与 GitHub 协作利器(四)Node.js 与 npm 核心环境 你的第一个Electron应用程序 前言 上…...
【STM32-学习笔记-11-】RTC实时时钟
文章目录 RTC实时时钟一、RTC简介二、RTC框图三、RTC基本结构四、RTC操作注意事项五、RTC函数六、配置RTCMyRTC.c 七、示例:实时时钟①、main.c②、MyRTC.c③、MyRTC.h RTC实时时钟 一、RTC简介 RTC(Real Time Clock)实时时钟 RTC是一个独立…...
使用ffmpeg提高mp4压缩比,减小文件体积【windows+ffmpeg+batch脚本】
文章目录 关于前情提要FFmpeg是什么使用脚本运行FFmpeg首先,下载ffmpeg.exe然后在视频相同位置写一个bat脚本运行压缩脚本 关于 个人博客,里面偶尔更新,最近比较忙。发一些总结的帖子和思考。 江湖有缘相见🤝。如果读者想和我交…...
PostgreSQL-01-入门篇-简介
文章目录 1. PostgreSQL是什么?2. PostgreSQL 历史 2.1. 伯克利 POSTGRES 项目2.2. Postgres952.3. PostgreSQL来了 3. PostgreSQL vs MySQL4. 安装 4.1 Windows 安装4.2 linux 安装4.3 docker安装 1. PostgreSQL是什么 PostgreSQL 是一个基于加州大学伯克利分校计算机系开…...
虚拟专用网VPN的概念及实现VPN的关键技术
虚拟专用网VPN通过建立在公共网络上的重要通道(1分),实现远程用户、分支机构、业务伙伴等与机构总部网络的安全连接,从而构建针对特定组织机构的专用网络,实现与专用网络类似的功能,可以达到PN安全性的目的,同时成本相对要低很多(…...
电脑风扇声音大怎么办? 原因及解决方法
电脑风扇是电脑的重要组件之一,它的作用是为电脑的各个部件提供冷却,防止电脑过热。然而,有时候我们会发现电脑风扇的声音特别大,不仅影响我们的使用体验,也可能是电脑出现了一些问题。那么,电脑风扇声音大…...
【Pytorch】unsqueeze与expand结合使用
示例代码 mask mask.unsqueeze(1).expand(-1, N, -1, -1)unsqueeze(1) 操作 unsqueeze是一个在指定位置增加维度的方法。在这行代码中,mask.unsqueeze(1)的作用是在mask张量的第二个维度(索引为1的位置)上插入一个新的维度。 例如…...
基于 Spring Boot 和 Vue.js 的全栈购物平台开发实践
在现代 Web 开发中,前后端分离的架构已经成为主流。本文将分享如何使用 Spring Boot 和 Vue.js构建一个全栈购物平台,涵盖从后端 API 开发到前端页面实现的完整流程。 1. 技术栈介绍 后端技术栈 JDK 1.8:稳定且广泛使用的 Java 版本。 Spring…...
MongoDB单机版安装
MongoDB单机版安装 在CentOS Linux release 7.9.2009 (Core)下安装MongoDB的步骤如下: 1 创建用户和组(可选,根据需要) 如果您希望以非root用户运行MongoDB服务,可以创建一个专用的用户和组。 groupadd mongodb us…...
HTTP/2 与 HTTP/3 的新特性
一、引言 在互联网蓬勃发展的浪潮中,HTTP 协议作为网络通信的基石,历经多次迭代升级,不断推动着网络传输效率与性能的提升。从最初简单的 HTTP/0.9 版本,仅能实现基本的文本传输,到 HTTP/1.0 引入多种请求方法与头部信…...
【软件开发过程管理规范】需求管理,需求分析,设计开发管理,测试管理(Word)
一、需求管理规程 1 简介 2 过程总体描述 2.1 过程概述 2.2 过程流程图 3 过程元素描述 3.1 准备阶段 3.2 需求调研 3.3 需求分析 软件开发人员及用户往往容易忽略信息沟通,这导致软件开发出来后不能很好地满足用户的需要,从而造成返工。而返工不仅在技术…...
mysql的主从配置
#mysql数据库 #主从 MySQL数据库主从配置 1.MySQL主从介绍 MySQL 主从又叫做 Replication、AB 复制。简单讲就是 A 和 B 两台机器做主 从后,在 A 上写数据,另外一台 B 也会跟着写数据,两者数据实时同步的。 MySQL 主从是基于 binlog 的&…...
debian中apt的配置与解析
引言 在系统使用过程中,我们可能会遭遇 apt update 操作出现问题,或者 apt upgrade 速度迟缓的情况。这往往是由于所使用软件源本身存在诸如服务器性能不佳、维护不及时等质量问题,同时,软件源服务器与我们所处地理位置的距离较远…...
Python Pyside6 加Sqlite3 写一个 通用 进销存 系统 初型
图: 说明: 进销存管理系统说明文档 功能模块 1. 首页 显示关键业务数据商品总数供应商总数本月采购金额本月销售金额显示预警信息库存不足预警待付款采购单待收款销售单2. 商品管理 商品信息维护商品编码(唯一标识)商品名称规格型号单位分类进货价销售价库存数量预警…...
Java工程结构:服务器规约(JVM 碰到 OOM 场景时输出 dump 信息、设置tomcat的 JVM 的内存参数、了解服务平均耗时)
文章目录 I 调用远程操作必须有超时设置。II 推荐了解每个服务大致的平均耗时JVM 的 Xms 和 Xmx 设置一样大小的内存容量让 JVM 碰到 OOM 场景时输出 dump 信息调大服务器所支持的最大文件句柄数(File Descriptor,简写为 fd)高并发服务器建议调小 TCP 协议的 time_wait 超时…...
Spring经典面试题
在Spring的面试中,经常会被问到一些经典的问题,这些问题涵盖了Spring的基本概念、核心特性、工作原理以及在实际项目中的应用。以下是一些Spring面试中最经典的题目: 一、Spring概述 什么是Spring框架?Spring框架有哪些主要模块&…...
以太网实战AD采集上传上位机——FPGA学习笔记27
一、设计目标 使用FPGA实现AD模块驱动采集模拟电压,通过以太网上传到电脑上位机。 二、框架设计 数据位宽转换模块(ad_10bit_to_16bit):为了方便数据传输,数据位宽转换模块实现了将十位的 AD 数据转换成十六位&#…...