单调栈
单调栈是一种特殊的栈数据结构,它可以用来解决一类与单调性相关的问题。单调栈在处理一些需要维护元素单调性的场景中非常有用,例如寻找数组中每个元素右边第一个比它大(小)的数等问题
单调栈分为单调递增栈和单调递减栈两种类型:
单调递增栈:当一个新元素要入栈时,如果它比栈顶元素大,则直接入栈 .(取大)
单调递减栈:当一个新元素要入栈时,如果它比栈顶元素小,则直接入栈.(取小)
题目描述
给出项数为 n 的整数数列 an。
定义函数 f(i) 代表数列中第 i 个元素之后第一个大于 ai 的元素的下标,即 {}f(i)=mini<j≤n,aj>ai{j}。若不存在,则 f(i)=0。
试求出 f(1…n)。
#include <stdio.h>
#include <stdlib.h>
// 定义栈结构体
typedef struct {
int* a; // 数组指针
int top; // 栈顶指针
int size; // 栈大小
} Stack;
// 初始化栈
void initStack(Stack* stack, int size) {
stack->a = (int*)malloc(size * sizeof(int));
stack->top = -1;
stack->size = size;
}
// 判断栈是否为空
int isEmpty(Stack* stack) {
return stack->top == -1;
}
// 判断栈是否已满
int isFull(Stack* stack) {
return stack->top == stack->size - 1;
}
// 入栈
void push(Stack* stack, int value) {
if (isFull(stack)) {
printf("Stack is full.\n");
return;
}
stack->a[++(stack->top)] = value;
}
// 出栈
int pop(Stack* stack) {
if (isEmpty(stack)) {
printf("Stack is empty.\n");
return -1;
}
return stack->a[(stack->top)--];
}
// 获取栈顶元素
int peek(Stack* stack) {
if (isEmpty(stack)) {
printf("Stack is empty.\n");
return -1;
}
return stack->a[stack->top];
}
// 单调栈算法
void ddStack(int* a, int n, int* result) {
Stack stack;
initStack(&stack, n);
for (int i = 0; i < n; i++) {
while (!isEmpty(&stack) && a[peek(&stack)] < a[i]) {
result[pop(&stack)] = i + 1;
}
push(&stack, i);
}
while (!isEmpty(&stack)) {
result[pop(&stack)] = 0;
}
}
int main() {
int n;
printf("请输入数列的项数:");
scanf("%d", &n);
int* a= (int*)malloc(n * sizeof(int));
printf("请输入数列的元素:");
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
int* result = (int*)malloc(n * sizeof(int));
ddStack(a, n, result);
printf("f(1...%d) = ", n);
for (int i = 0; i < n; i++) {
printf("%d ", result[i]);
}
printf("\n");
free(a);
free(result);
return 0;
}
树
在计算机科学和数据结构领域,树是一种重要的数据结构。它是一种非线性结构,由节点和边组成。树的概念类似于现实生活中的树,有根、分支和叶子。
-
树的基本概念 树由节点和边组成。每个节点都可以有零个或多个子节点,而除了根节点外,每个节点都有一个父节点。根节点是树的顶层节点,它没有父节点。叶子节点是没有子节点的节点。
-
树的存储结构的表示:a.双亲表示法
#include <stdio.h>
#define MAX_SIZE 100
typedef struct TreeNode {
int value;
int parentIndex;
} TreeNode;
int main() {
TreeNode tree[MAX_SIZE]; // 定义一个包含最大节点数的数组
int n; // 树的节点数量
scanf("%d", &n);
// 初始化树的所有节点
for (int i = 0; i < n; i++) {
printf("输入第%d个节点的值:", i + 1);
scanf("%d", &(tree[i].value));
tree[i].parentIndex = -1; // 初始时将所有节点的父节点索引设为-1
}
// 输入每个节点的父节点索引
for (int i = 1; i < n; i++) {
int index, parentIndex;
printf("输入节点%d的父节点索引:", i);
scanf("%d", &parentIndex);
if (parentIndex >= 0 && parentIndex < i) { // 父节点索引合法性判断
tree[i].parentIndex = parentIndex;
} else {
printf("父节点索引无效!\n");
i--; // 重新输入当前节点的父节点索引
}
}
// 输出每个节点的值及其父节点的值
printf("节点及其父节点信息:\n");
for (int i = 0; i < n; i++) {
printf("节点%d的值:%d,父节点的值:", i, tree[i].value);
if (tree[i].parentIndex == -1) {
printf("根节点\n");
} else {
printf("%d\n", tree[tree[i].parentIndex].value);
}
}
return 0;
}
-
b.孩子表示法 (暂时不会)
-
c.孩子兄弟表示法
-
二叉树 二叉树是一种特殊的树结构,每个节点最多只能有两个子节点。一个子节点称为左子节点,另一个称为右子节点。二叉树的特点使得它在计算机科学中应用广泛,例如在搜索算法和排序算法中。 ( 目前还是粗略的了解)
-
树的遍历 树的遍历是指按照一定规则访问树中的所有节点。常用的遍历方法有三种:前序遍历、中序遍历和后序遍历。前序遍历先访问根节点,然后按照左子树、右子树的顺序遍历;中序遍历先访问左子树,然后访问根节点,最后访问右子树;后序遍历先访问左子树,然后访问右子树,最后访问根节点。
-
树的应用 树在计算机科学和软件工程中有广泛的应用。例如,在文件系统中,文件和文件夹可以组织成树形结构;在数据库中,索引结构通常使用树来提高查询效率;在人工智能中,决策树可以用于分类和预测等任务。