1.数据结构的存储一般常用的有几种?各有什么特点?
数据结构的存储一般常用的有两种:顺序存储结构和链式存储结构。
- 顺序存储结构:比如数组,1-2-3-4-5-6-7-8-9-10,存储是按顺序的,再比如栈和队列等。
- 链式存储结构:链式存储结构是根据地址进行存储的,每一个存储数据后面跟着一个地址,并且存储形式不再是顺序的。
2.集合结构 线性结构 树形结构 图形结构
- 集合结构:一个集合,就是一个圆圈内很多个元素,元素与元素之间没任何关系。
- 线性结构:一个线上站着很多个人,这条线不一定是直的,线性结构是一对一的关系。
- 树形结构:类似于xml数据或者可以想象成金字塔,树形结构是一对多的关系。
- 图形结构:无边五向,多对多的关系。
3.单向链表 双向链表 循环链表
单向链表: A->B->C->D->E->F->G->H,单向链表A是头,H是尾,像一个只有一个头的火车一样 只能一个头拉着跑
双向链表:
循环列表:循环链表是与单向链表一样,是一种链式的存储结构,所不同的是,循环链表的最后一个结点的指针是指向该循环链表的第一个结点或者表头结点,从而构成一个环形的链。发挥想象力 A->B->C->D->E->F->G->H->A. 绕成一个圈。就像蛇吃自己的这就是循环 。
4.数组和链表的区别
- 数组:数组元素在内存上是连续存放的,可以通过下标快速查找,插入和删除需要移动大量元素,比较适用于元素变化很少的情况。
- 链表:链表中的元素在内存中不是顺序存储的,查找速度慢,插入和删除只需要对元素指针重新赋值,效率高。
5.堆、栈和队列
堆:
- 堆是一种经过排序的树形数据结构,每个节点都有一个值,通常我们所说的堆的数据结构是指二叉树。所以堆在数据结构中通常可以被看作是一棵树的数组对象。而且堆需要满足以下两个性质:(1)堆中某个节点的值总是不大于或者不小于其父节点的值;(2)堆总是一颗完全二叉树。
- 堆分为两种情况,有最大堆和最小堆。将根节点最大的堆叫做最大堆,根节点最小的堆叫做最小堆,在一个摆放好元素的最小堆中,父节点的元素一定比子节点的元素要小,但对于左右节点的大小,并没有规定谁大谁小。
- 堆常用来实现优先队列,堆的存取是随意的,就如同我们在图书馆的书架上取书,虽然书的摆放是有序的,但我们不需要按顺序取某一本书,而是直接找到我们想要的书。
栈
- 栈是限定在表尾进行插入和删除操作的线性表。我们把允许插入和删除的一端叫做栈顶,另一端称为栈底,不含任何数据元素的栈为空栈。栈的特殊之处在于它限制了这个线性表的的插入和删除位置,自始至终只能在栈顶进行操作。
- 栈是一种具有后进先出的数据结构,又被称为后进先出的线性表,简称LIFO(Last In First Out)结构。也就是说后存放的先取,先存放的后取,这就类似于我们要在取放在箱子底部的东西(放进去比较早的物体),我们首先要移开压在它上面的物体(放进去比较晚的物体)。
- 堆栈中定义了一些操作,最重要的是push和pop,push操作是在堆栈的顶部加入一个元素。pop操作相反,在堆栈的顶部移去一个元素,并将堆栈的大小减一。
- 栈的应用-递归。
队列
- 队列是只允许在一端进行插入操作,另一端进行删除操作的线性表。允许插入的一端被称为队尾,允许删除的一端被称为队头。他是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,在表的后端进行插入操作,队列是一种操作手限制的表。
- 队列是一种先进先出的数据结构,又称为先进先出的线性表,简称 FIFO(First In First Out)结构。也就是说先放的先取,后放的后取。
6.输入一颗二叉树的根节点,求该树的深度?
- 如果一棵树只有一个结点,它的深度为1。
- 如果根结点只有左子树而没有右子树,那么树的深度应该是其左子树的深度加1;同样如果根结点只有右子树而没有左子树,那么树的深度应该是其右子树的深度加1。
- 如果既有右子树又有左子树,那该树的深度就是其左、右子树深度的较大值再加1。
实现:
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
}
int TreeDepth(TreeNode *root)
{
if(root == NULL)
{
return 0;
}
int left = TreeDepth(root->left);
int right = TreeDepth(root->right);
return (left > right)?left:right;
}
7.输入一颗二叉树的根节点,判断是不是平衡二叉树?
- 重复遍历节点:先求出根节点的左右子树的深度,然后判断他们的深度相差不超过1,如果否,则不是一颗平衡二叉树;如果是,在用同样的发方法分别判断左子树和右子树是否是平衡二叉树,如果都是,则这就是一颗平衡二叉树。
- 遍历一遍节点:遍历节点的同时记录下节点的深度,避免重复访问。
实现:
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
}
int TreeDepth(TreeNode *root)
{
if(root == NULL)
{
return 0;
}
int left = TreeDepth(root->left);
int right = TreeDepth(root->right);
return (left > right)?left:right;
}
bool isBalanced(TreeNode *root)
{
if(root == NULL)
{
return true;
}
int left = TreeDepth(root->left);
int right = TreeDepth(root->right);
int diff = left - right;
if(diff > 1|| diff < -1)
return false;
return isBalanced(root->left) && isBalanced (root->right);
}