仅供参考!!!
必背知识点
数据结构 是相互之间存在一种或多种特定关系的数据元素的集合
数据结构的三要素:
逻辑结构,存储结构,数据的运算(定义(逻辑结构的,运算的功能)和实现(物理结构的,运算的具体操作步骤))
逻辑结构:数据元素之间的逻辑关系,与数据的存储无关,独立于计算机,线性结构和非线性结构
存储结构:数据结构在计算机中的表示
顺序存储:逻辑上相邻,物理上也相邻
链式存储:逻辑上相邻,物理上可以不相邻
索引表:在存储信息时,还需要建立附加的索引表
哈希表:根据关键字,直接计算出该元素的存储地址。
算法:对特定问题求解步骤的一种描述
基本特性:有确可叔叔
有穷性:算法在有穷步之后结束,并且每一步都在有穷时间内完成
确定性:算法中每条指令都是有确定含义的,对于同一输入,有同一输出
可行性:算法中描述的操作可以根据现有实现的基本运算执行有限次后完成
输入:一个或多个输入
输出:一个或多个输出,这些输出和输入有着某种关系
好的算法:正可健效
正确性:算法能正确的求解问题
可读性:算法应该有良好的可读性
健壮性:输入非法数据是,可以对这些错误操作进行处理
效率和低存储需求:执行时间和所需最大空间内存
时间复杂度:一个算法所需花费的时间,和问题规模n有关
空间复杂度:一个算法在运行过程中临时占用存储空间的大小
线性表:由n个相同数据类型的数据元素的构成的有序序列,逻辑关系,表示一对一的相邻关系
相关操作:求表长,定位元素位置下标,初始化表,表得插入,表得删除,输出表,判断表是否为空
顺序表:线性表的顺序存储,他是用一组地址连续的存储单元依次存储线性表中的数据元素,从而使得在逻辑上相邻,物理上也相邻。支持随机访问,存储密度高,创建数组成功后不可再次更改数组大小,插入和删除需要移动大量数组元素。
单链表:线性表的链式存储,一组任意的存储单元来存储线性表中的数据元素。插入和删除的效率较高,没有元素个数的限制,不支持随机存储
双链表:两个指针域,,一个指针域指向其前驱,一个指向其后继节点
循环链表:尾结点指向其头结点
栈只允许在一段进行插入和删除的线性表,进行插入和删除的一端称栈顶,不进行插入和删除的一段称为栈底。后进先出
栈的基本操作包含:入栈,出栈,判断栈是否为空,是否已满,栈的初始化等
栈的实现:
顺序栈:顺序表的实现,存在溢出的风险,链栈:使用链表实现,不存在溢出的情况
队列是限制操作的线性表,只能在一段删除,一端插入,先进先出
基本操作:入队,出队,判断队满,对空,初始化等
队列的实现:
循环队列:使用顺序表实现,利用取模的方式,从逻辑上看是一个环形
链队:使用链表实现,用两个指针标记队列的头部和尾部,优点是不会存在队列慢的情况
判断队满:牺牲一个元素空间,利用一个标记位
数组由n个相同数据类型的数据元素构成的有序序列,是线性表的推广,一维数组可以看做线性表,二维数组可以将其元素看成定长线性表,下标的取值范围称为维界。
广义表:由0个或者多个,元素或子表组成的有序序列,线性表的推广
两个基本操作:
取表头:广义表中的第一个元素
取表尾:取出广义表中除第一个元素以外的其他元素
串是由零个或多个字符组成的有限序列
串的实现:
顺序存储:用一组连续的存储空间依次存储串中的元素,删除和插入需要移动大量的元素
链式存储:用一组非连续的存储空间存储串中的元素,不需要移动大量元素
串的基本操作:串的复制,求串长,求子串,串联接,串的销毁
哈希表:根据关键码值而直接进行访问的数据结构
树
树是n个结点的有限集,它或为空树; 或为非空树,对于非空树T:
(1)有且仅有一个称之为根的结点;
(2)除根结点以外的其余结点可分为 m个互不相交的有限集 Ti , T2 , …,几,其中每一个集合本身又是一棵树,并且称为根的子树
性质
树中一个结点的孩子个数称为该结点的度。
-
树中结点n的个数:n = n0+n1+n2+…+1
二叉树
是n个结点所构成的集合,它或为空树(n= 0); 或为非空树,
对于非空树T:
(1) 有且仅有一个称之为根的结点;
(2)除根结点以外的其余结点分为两个互不相交的子集T1和T2, 分别称为T的左子树和右子树且T1和T2本身又都是二叉树
满二叉树:深度为 K 且含有 2^k-1个结点的二叉树
完全二叉树:深度为K的, 有n个结点的二叉树, 当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时, 称之为完全二叉树
由先序,中序和后序,中序遍历可以得到唯一一个二叉树
二叉树的遍历:按照某条搜索路径访问树中每个节点,使得每个节点都被访问依次且仅被访问一次
二叉排序树:根节点的左边元素均小于根节点,右边均大于根节点,其左右孩子也满足这一条件
性质
-
对任何一棵二叉树T, 如果其终端结点数为n0,度为2的结点数为n2,则n0 = n2+1
-
非空二叉树上第K层至多有2^(k-1)个结点
-
高度/深度为h的二叉树至多有2^h-1 个结点,至少2^(h-1)个结点
-
-
具有 n 个结点的完全二叉树的深度/高度
-
n个结点的二叉树采用链式存储,其中空指针为 n+1
平衡二叉树的插入
为了避免树的高度增长过快,影响二叉排序树的性能,在二叉树进行插入和删除时,需要确保左子树的高度减去右子树的高度只差小于等于一
LL:结点A左孩子的左结点上插入结点。todo:右旋,A左孩子的右子树为A的左孩子
RR:结点A右孩子的右结点上插入结点。todo:左旋,A右孩子的左孩子为A的右孩子
LR:结点A左孩子的右孩子上插入结点。todo:先左旋转后右旋转,插入点为C,C的左孩子为B,右孩子为A。C的左孩子放到调整后结点的左边下,右孩子放到右边。
RL:结点A右孩子的左孩子上插入结点。todo:先右旋后左旋,插入点为C,C的左孩子为A,右孩子为B。C的左孩子放到调整后结点的左边下,右孩子放到右边。
哈夫曼树
带路径长度最小的二叉树即为哈夫曼树
带权路径长度:从树的根到任意结点的经过边数与该结点上权值的乘积。
树中所有结点的带权路径长度之和称为该树的带权路径长度WPL。
哈夫曼树中不存在度为1的结点
n个叶子结点的哈夫曼树总结点数2n-1
图
图 G由两个集合V和E组成,记为G=(V,E),其中V是顶点的有穷非空集合,E是V中顶点偶对的有穷集合,这些顶点偶对称为边。V(G)和E(G)通常分别表示图G的顶点集合和边集合,E(G)可以为空集。若E(G)为空,则图G只有顶点而没有边。
对于图G,若边集E( G)为有向边的集合,则称该图为有向图;若边集E( G)为无向边的集合,则称该图为无向图。
完全图:全图中任意两个顶点之间都存在边 ,共n(n-1)/2条边
n个顶点的有向完全图有n(n-1)条边
搜索性能分析
邻接表:o(v+e)
邻接矩阵:o(v^2)
关键路径
源点到汇点的最长路径
关键活动:边上的权值增加,将导致关键路径变化的活动
最早发生时间:v1-vk的最长路径长度
最迟发生时间:总时间-(vk-vj的路径长度)
最早开始时间:最早发生时间
最晚开始时间:总时间 -(vk-vj的路径长度) - vk完成所需时间
最短路径:带权路径长度最短的那条路径
拓扑序列:由 一个有向无环图的顶点组成的序列
满足:
一个顶点只出现一次
顶点a在顶点b之前,则不存在由顶点b到顶点a的边
算法步骤:
选择一个没有前驱的顶点输出
删除改顶点和所有以它为起点的有向边
重复上述过程直至当前网中不存在无前驱的顶点为止
排序
名称 | 方式 | 存储 | 空间 | 时间 | 稳定性 |
---|---|---|---|---|---|
直接插入 | 将数组分为三部分,已排序区,待排序元素,待排序区,每一次将待排元素和已排序区的元素进行比较,待排元素放到数组0的位置,如果大于之前的元素位置为i,已排序区整体后移一位,将待排元素插入,以此往复比较n-1次 | 顺序链式 | 1 | n2 | 稳定 |
折半插入 | 再插入排序的基础上,增加了查找的效率,其他点不变 | 顺序 | 1 | n2 | 稳定 |
希尔排序 | 缩小增量排序,增量分组,每一个分组都是插入排序,每一次的增量为上一次增量的一半,一趟就是增量的比较次数 | 顺序 | – | – | 不稳定 |
冒泡排序 | 将i个元素和i-1个元素进行比较,如果发现i-1个元素大于第i个元素,则交换二者位置,每一趟排序都有一个元素再最终位置上。 | 顺序链式 | 1 | n2 | 稳定 |
快速排序 | 根据一个枢纽,从后往前找出小于枢纽的值,放到low处,从前往后找出第一个大于枢纽的值,将第high处,以此往返直至low==high,将枢纽值放到low处,完成一趟排序 | 顺序 | logn | nlog2n | 不稳定 |
选择排序 | 将数组分为已排序区和待排序区,每一趟都是从n-i+1个元素中选择一个最小的元素和当前第i个元素进行互换,一趟确定一个最终位置 | 顺序链式 | 1 | n2 | 不稳定 |
归并排序 | 将两个或两个以上的有序表组合成一个新的有序表 | 顺序 | n | nlog2n | 稳定 |
堆排序 | 从小根堆或者大根堆中选择根节点然后和末尾元素互换位置,将末尾位置输出,最好对树继续调整 | 链式 | 1 | nlog2n | 不稳定 |
数据压缩
- 对称矩阵:存放数组大小n(n+1)/2
- 下三角(含主对角线):i(i-1)/2+j-1
- 上三角:j(j-1)/2+i-1
- 稀疏矩阵:三元组
ASL
顺序表
成功:n+1/2
失败:n
二叉树
成功:(每层结点数*高度)之和/总结点数
失败:(空余结点数*空结点父节点高度)之和/总结点数+1
散列表
成功:探测次数之和/数据总数
失败:比较次数(后续结点为空比较失败)之和/数据总数+1
线索二叉树
若无左子树,则将左指针指向其前驱结点;
若无右子树,则将右指针指向其后继结点。
贪心算法:只寻求局部最优解,不从整体出发,得到的最终结果可能不是最优解,从上往下,一步一步得到结果
动态规划:将一个大问题分为若干个子问题,这些子问题可能重复,为防止记录重复,可以将它们记录下来,从下往上,且前一个子问题对后一个子问题必然产生影响,最终一步一步地到最优解。
分治法:将一个大问题分成若干个子问题,使用递归求解,子问题之前相互独立,子问题最终的解的合集就为最优解。
查找:在数据集合中,找出满足某种条件的数据元s素的过程。
查找表:用于查找数据的集合
关键字:数据元素中唯一标识该数据项的值
平均查找长度:一次查找需要比较关键字的次数
顺序表
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct
{
int *arr;
int max, len;
} Sqlist;
void InitList(Sqlist *list)
{
int x, i;
printf("input max:");
scanf("%d", &x);
list->arr = (int *)malloc(sizeof(int) * x);
list->len = 0;
list->max = x;
}
int Length(Sqlist list)
{
return list.len;
}
int LocateElem(Sqlist list, int e)
{
int res = -1;
for (int i = 0; i < list.len; i++)
{
if (e == list.arr[i])
{
res = i + 1;
break;
}
}
return res;
}
int GetElem(Sqlist list, int i)
{
return list.arr[i - 15];
}
bool ListInsert(Sqlist *list, int i, int e)
{
if (i < 1 || i > list->len + 1 || list->len == list->max)
{
return false;
}
for (int j = list->len; j >= i; j--)
{
list->arr[j] = list->arr[j - 1];
}
list->arr[i - 1] = e;
list->len++;
return true;
}
bool ListDelete(Sqlist *list, int i, int *e)
{
if (i < 1 || i > list->len)
{
return false;
}
e = &list->arr[i - 1];
for (int j = i; j < list->len; j++)
{
list->arr[j - 1] = list->arr[j];
}
list->len--;
return true;
}
void PrintList(Sqlist list)
{
for (int i = 0; i < list.len; i++)
{
printf("%d ", list.arr[i]);
}
putchar('\n');
}
bool Empty(Sqlist list)
{
if (list.len == 0)
{
return true;
}
return false;
}
void DestoryList(Sqlist *list)
{
free(list->arr);
list->arr = NULL;
list->len = 0;
list->max = 0;
}
void main()
{
Sqlist list;
int x;
InitList(&list);
for (int i = 0; i < 4; i++)
{
list.arr[i] = i;
}
list.len = 4;
PrintList(list);
printf("pos:%d\n", LocateElem(list, 1));
printf("ele:%d\n", GetElem(list, 2));
printf("len:%d\n", Length(list));
ListInsert(&list, 2, 333);
PrintList(list);
ListDelete(&list, 1, &x);
PrintList(list);
DestoryList(&list);
}
链表
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct LNode
{
int Data;
struct LNode *next;
} LNode, *linkList;
linkList HeadInsert(linkList list)
{
int x, i;
LNode *s;
printf("input len:");
scanf("%d", &x);
list = (LNode *)malloc(sizeof(LNode));
list->next = NULL;
for (i = 0; i < x; i++)
{
s = (LNode *)malloc(sizeof(LNode));
s->Data = i + 1;
s->next = list->next;
list->next = s;
}
return list;
}
linkList tailInsert(linkList list)
{
int x, i;
LNode *s, *h;
printf("input len:");
scanf("%d", &x);
h = list = (LNode *)malloc(sizeof(LNode));
for (i = 0; i < x; i++)
{
s = (LNode *)malloc(sizeof(LNode));
s->Data = i + 1;
s->next = NULL;
list->next = s;
list = s;
}
return h;
}
LNode *Getelem(linkList list, int i)
{
LNode *s;
int j = 1;
list = list->next;
while (list && i > 0)
{
if (i == j)
{
break;
}
j++;
list = list->next;
}
return list;
}
LNode *LocateElem(linkList list, int e)
{
LNode *s = list->next;
while (s)
{
if (e == s->Data)
{
break;
}
s = s->next;
}
return s;
}
void printNode(linkList list)
{
list = list->next;
while (list)
{
printf("%d ", list->Data);
list = list->next;
}
putchar('\n');
}
void InsertNode(linkList list, int i, int e)
{
LNode *s, *p = Getelem(list, i - 1);
s->next = p->next;
p->next = s;
s->Data = e;
}
void deleteNode(linkList list, int i)
{
LNode *s, *p, *f;
p = Getelem(list, i - 1);
f = p->next;
p->next = f->next;
free(f);
}
int len(linkList list)
{
int i = 0;
list = list->next;
while (list)
{
i++;
list = list->next;
}
return i;
}
void main()
{
LNode *p, *s;
p = HeadInsert(p);
printNode(p);
s = tailInsert(s);
printNode(s);
deleteNode(s, 2);
printNode(s);
// InsertNode(p, 1, 4);
// printNode(p);
printf("%d ", len(s));
}
顺序栈
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define maxsize 10
typedef struct
{
int top;
int list[maxsize];
} stack;
stack *initStack()
{
stack *s = (stack *)malloc(sizeof(stack));
s->top = -1;
for (int i = 0; i < maxsize; i++)
{
s->list[i] = 0;
}
return s;
}
bool enStack(stack *s, int e)
{
if ((s->top + 1) == maxsize)
{
return false;
}
s->list[++(s->top)] = e;
printf("e:%d\n", s->list[s->top]);
return true;
}
bool popStack(stack *s, int *x)
{
if (s->top - 1 == -2)
{
return false;
}
*x = s->list[s->top--];
printf("x:%d\n", *x);
return true;
}
bool empty(stack *s)
{
if (s->top == -1)
{
return true;
}
return false;
}
void main()
{
stack *s;
int x;
s = initStack();
enStack(s, 1);
enStack(s, 2);
popStack(s, &x);
popStack(s, &x);
if (empty(s))
{
printf("true");
}
}
链栈(带头结点)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node
{
int data;
struct node *next;
} stack;
stack *initStack()
{
stack *s = (stack *)malloc(sizeof(stack));
s->next = NULL;
return s;
}
bool enStack(stack *s, int e)
{
stack *node = (stack *)malloc(sizeof(stack));
node->data = e;
node->next = s->next;
s->next = node;
return true;
}
bool popStack(stack *s, int *x)
{
stack *p = s->next;
s->next = p->next;
printf("%d\n", p->data);
free(p);
return true;
}
bool empty(stack *s)
{
if (s->next == NULL)
{
return true;
}
return false;
}
void main()
{
stack *s;
int x;
s = initStack();
enStack(s, 1);
enStack(s, 2);
popStack(s, &x);
popStack(s, &x);
if (empty(s))
{
printf("true");
}
}
队列
#include <stdio.h>//顺序队
#include <stdlib.h>
#include <stdbool.h>
#define maxsize 10
typedef struct
{
int data[maxsize];
int front, rear;
} Squeue;
Squeue *initQueue()
{
Squeue *s = (Squeue *)malloc(sizeof(Squeue));
s->front = s->rear = 0;
return s;
}
bool empty(Squeue *s)
{
if (s->front == s->rear)
{
return true;
}
return false;
}
bool enQueue(Squeue *s, int e)
{
if (s->front == (s->rear + 1) % maxsize)
{
return false;
}
s->data[s->rear] = e;
printf("%d ", s->data[s->rear]);
s->rear = (s->rear + 1) % maxsize;
return true;
}
bool popQueue(Squeue *s)
{
if (empty(s))
{
return false;
}
printf("%d ", s->data[s->front]);
s->front = (s->front + 1) % maxsize;
return true;
}
void main()
{
Squeue *s;
int x;
s = initQueue();
for (int i = 0; i < maxsize - 2; i++)
{
enQueue(s, i);
}
putchar('\n');
if (enQueue(s, 122))
{
printf("true");
}
}
链队
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define maxsize 10
typedef struct Node
{
int data;
struct Node *next;
} Node;
typedef struct
{
Node *front, *rear;
} Squeue;
Squeue *initQueue(Squeue *s)
{
s->front = s->rear = (Node *)malloc(sizeof(Node)); //头结点
s->front->next = NULL;
return s;
}
bool empty(Squeue *s)
{
if (s->front == s->rear)
{
return true;
}
return false;
}
void enQueue(Squeue *s, int e)
{
Node *q = (Node *)malloc(sizeof(Node));
q->data = e;
q->next = NULL;
s->rear->next = q;
s->rear = q;
}
bool popQueue(Squeue *s, int *x)
{
if (empty(s))
{
return false;
}
Node *q = s->front->next;
*x = q->data;
s->front->next = q->next;
if (q == s->rear)
{
s->rear = s->front;
}
free(q);
return true;
}
void main()
{
Squeue *s;
int x;
s = initQueue(s);
for (int i = 0; i < maxsize; i++)
{
enQueue(s, i);
}
putchar('\n');
popQueue(s, &x);
printf("%d ", x);
popQueue(s, &x);
printf("%d ", x);
popQueue(s, &x);
printf("%d ", x);
}
括号配对
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define maxsize 10
typedef struct
{
char data[maxsize];
int top;
} stack;
stack *InitStack(stack *s)
{
s = (stack *)malloc(sizeof(stack));
s->top = -1;
return s;
}
bool stackEmpty(stack *s)
{
if (s->top == -1)
{
return true;
}
return false;
}
bool Push(stack *s, char e)
{
if (s->top + 1 == maxsize)
{
return false;
}
s->data[++(s->top)] = e;
return true;
}
bool Pop(stack *s, char *e)
{
if (stackEmpty(s))
{
return false;
}
*e = s->data[s->top--];
return true;
}
bool brecketCheck(char str[], int len)
{
stack *s;
char tmp;
s = InitStack(s);
if (len % 2 != 0)
{
return false;
}
for (int i = 0; i < len; i++)
{
if (str[i] == '(' || str[i] == '{' || str[i] == '[')
{
Push(s, str[i]);
}
else
{
if (stackEmpty(s))
{
return false;
}
Pop(s, &tmp);
printf("%c : %c \n", tmp, str[i]);
if ((str[i] == '}' && tmp != '{') || (str[i] == ']' && tmp != '[') || (str[i] == ')' && tmp != '('))
{
return false;
}
}
}
return stackEmpty(s);
}
void main()
{
char data[maxsize];
data[0] = '(';
data[1] = '{';
data[2] = '[';
data[3] = ']';
data[4] = '}';
data[5] = ']';
if (brecketCheck(data, 6))
{
printf("true");
}
else
{
printf("false");
};
}