数据结构
应用题
1、顺序表的插入
Status ListInsert(Sqlist &L, int i, ElemType e){
//在顺序表L中第i个位置插入新的元素e,i的合法范围是1<=i<=L.length+1
if((i<1)||(i>L.length+1)) return ERROR;//i值不合法
if(L.length==MAXSIZE) return ERROR;//当前存储空间已满
for(j=L.length-1;j>=i-1;j--){
L.elem[j+1]=L.elem[j];//插入位置及之后的元素后移
}
L.elem[i-1]=e;//将新元素e放在第i位置
++L.length;//表长加1
return OK;
}
2、顺序表的删除
Status ListDelete(SqList &L,int i){
//在顺序表L中删除第i个元素,i值合法范围是1<=i<=L.length
if((i<1)||(i>L.length)) return ERROR;//i值不合法
for(j=i;j<=L.length-1;j++){
L.elem[j-1]=L.elem[j];//被删除元素之后的元素前移
}
--L.length;//表长减1
return OK;
}
3、链栈的入栈
Status Push(LinkStack &S, SElemType e){
//在栈顶插入元素e
p=new StackNode;//生成新节点
p->data=e;//将新节点数据域置为e
p->next=S;//将新节点插入栈顶
S=p;//修改栈顶指针为p
return OK;
}
4、链栈的出栈
Status Pop(LinkStack &S,SElemType &e){
//删除S的栈顶元素,用e返回其值
if(S==NULL) return ERROR;//栈空
e=S->data;//将栈顶元素赋给e
p=S;//用p临时保存栈顶元素空间,以备释放
S=S->next;//修改栈顶指针
delete p;//释放原栈顶元素的空间
return OK;
}
5、树和二叉树
-
树中一个结点的孩子个数称为该结点的度,树中结点的最大度数称为树的度
-
度大于0的结点称为分支结点(非终端结点);
度为0的结点称为叶子结点(终端结点)
-
结点的深度是从根结点开始自顶向下逐层累加
结点的高度是从叶结点开始自底向上逐层累加
树的高度(或深度)是树种结点的最大层数
-
树中两个结点之间的路径是由这两个结点之间所经过的结点序列构成的
路径长度是路径上所经过的边的个数
-
树的性质
-
二叉树的特点是每个结点至多只能有两颗子树(即二叉树不存在度大于2的结点),并且二叉树的子树有左右之分,其次序不能任意颠倒。
-
满二叉树
- 编号为i的结点,
- 若有双亲,则双亲为i/2;
- 若有左孩子,左孩子2i;
- 若有右孩子,右孩子2i+1
-
完全二叉树
- 对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。
- 若有度为1的结点,则只可能有一个,且该结点只有左孩子没有右孩子
- 按层序编号后,一旦出现某结点(编号为i)为叶子结点或只有左孩子,则编号大于i的结点都为叶子结点
- 若n为奇数,则每个分支结点都有左孩子和右孩子;若n为偶数,则编号最大的分支节点(n/2)只有左孩子没有右孩子。
-
二叉树的性质
-
-
二叉树的遍历
- 先序(NLR)
- 中序(LNR):根结点在中间,左边是左子树子孙,右边是右子树子孙
- 后序(LRN):最后一个结点是根结点
-
树和森林
- 树转换为二叉树的画法
- 在兄弟结点之间加一条线
- 对每个结点只保留它和第一个孩子的连线,抹去与其他孩子的连线
- 以树根为轴心,顺时针旋转45度
- 森林转换成二叉树的画法
- 将森林中的每颗树转换成相应的二叉树
- 每棵树的根也可视为兄弟结点,每棵树之间加一条连线
- 以第一棵树的根为轴心,顺时针旋转45度
- 树的遍历
- 先根遍历:与二叉树的先序遍历相同
- 后根遍历:与二叉树的中序遍历相同
- 森林的遍历
- 先序遍历
- 中序遍历
- 树转换为二叉树的画法
-
哈夫曼树
- 树中的结点常被赋予一个代表某种意义的数值,那个数值成为该结点的权
- 从树根到任意结点的路径长度(经过的边数)与该结点上权值的乘积,成为该结点的带权路径长度
- 树中所有叶子结点的带权路径长度之和成为该树的带权路径长度记为WPL
-
引入二叉线索树的目的是:加快查找结点的前驱和后继的速度
6、顺序有序表的合并
void MergeList_Sq(SqList LA,SqList LB,SqList &LC){
//已知顺序有序表LA和LB的元素按值非递减排列
//归并LA和LB得到新的顺序有序表LC,LC的元素也按值非递减排列
LC.length=LA.length+LB.length;//新表长度为待合并两表的长度之和
LC.elem=new ElemType[LC.length];//为合并后的新表分配一个数组空间
pc=LC.elem;//指针pc指向新表的第一个元素
pa=LA.elem; pb=LB.elem;//指针pa和pb的初值分别指向两个表的第一个元素
pa_last=LA.elem+LA.length-1;//指针pa_last指向LA最后一个元素
pb_last=LB.elem+LB.length-1;//指针pb_last指向LB最后一个元素
while((pa<=pa_last)&&(pb<=pb_last)){//未达到LA和LB的表尾
if(*pa<=*pb) *pc++=*pa++;//依次摘取两表中值较小的节点插入LC的最后
else *pc++=*pb++;
}
whlie(pa<=pa_last) *pc++=*pa++;//已到达LB表尾,依次将LA的剩余元素插入LC最后
whlie(pb<=pb_last) *pc++=*pb++;//已到达LA表尾,依次将LB的剩余元素插入LC最后
}
7、链式有序表的合并
void MergeList_L(LinkList &LA,LinkList &LB,LinkList &LC){
//已知单链表LA和LB的元素按值非递减排列
//归并LA和LB得到新的单链表LC,LC的元素也按值非递减排序
pa=LA->next;pb=LB->next;//pa和pb的初值分别指向两个表的第一个节点
LC=LA;//用LA的头节点作为LC的头节点
pc=LC;//pc的初值指向LC的头节点
while(pa&&pb){
//LA和LB均未到达表尾,依次摘取两表中值较小的节点插入到LC的最后
if(pa->data<=pb->data){//摘取pa所指节点
pc->next=pa;//将pa所指节点链接到pc所指节点之后
pc=pa;//pc指向pa
pa=pa->next;//pa指向下一节点
}else{//摘取pb所指节点
pc->next=pb;//将pb所指节点链接到pc所指节点之后
pc=pb;//pc指向pb
pb=pb->next;//pb指向下一节点
}
}
pc->next=pa?pa:pb;//将非空表的剩余段插入到pc所指节点之后
delete LB;//释放LB的头节点
}
一、绪论
-
数据:是客观事实的符号表示,是所有能输入计算机中并被计算机程序处理的符号总称。
-
数据结构:是相互之间存在一种或多种特定关系的数据元素的集合。
-
数据的****逻辑结构****是从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的。
-
逻辑结构层次图
-
算法的时间复杂度
找变的和不变的
二、线性表
-
线性表的四个特点
- 存在唯一的一个被称作“第一个”的数据元素
- 存在唯一的一个被称作“最后一个”的数据元素
- 除第一个元素之外,结构中的每个数据元素均只有一个前驱
- 除最后一个元素之外,结构中的每个数据元素均只有一个后继
-
顺序表查找算法的平均时间复杂度O(n)
一般情况下,在第i (1<=i<=n)个位置插入一个元素时,需从最后一个元素即第n个元素开始,依次向后移动一个位置,直至第i个元素(共n-i+1个元素)。
-
顺序表插入算法的平均时间复杂度O(n)
-
链表增加头节点的两个作用
- 便于首元节点的处理
- 便于空表和非空表的统一处理
-
有无头结点判断空表的条件
- 非空:头指针指向头结点
- 空表:头指针的指针域为空
- 判断空表的条件记为:L->next==NULL
-
删除算法的平均时间复杂度O(n)
-
循环链表指针的指向
表中最后一个节点的指针域指向头节点,整个链表形成一个环
-
顺序表的特点
- 顺序表可以随机存取(区别于:不可以随便读取栈和队列中间的某个数据)
- 存储密度高,每个结点只存储数据元素
- 逻辑上相邻的元素物理上也相邻,所以插入和删除操作需要移动大量元素
三、栈与队列
- 栈的特点:先进后出
- 只允许在一段进行插入和删除的线性表
- 栈顶:允许插入删除的一端(表尾端)
- 栈底:不允许插入删除的另一端(表头端)
- 空栈:不含任何元素的空表
- 队列的特点:先进先出
- 只允许在表的一端插入,在表的另一端删除
- 向队列插入元素称为入队或进队;删除元素称为出队或离队
- 队头:允许删除的一端,又称队首
- 队尾:允许插入的一端
- 队列为空的条件:Q.front==Q.rear
- 栈和队列的共同点:只允许在端点处插入和删除元素
- 一个递归算法必须包括:终止条件和递归部分
四、串、数组和广义表
五、树和二叉树
详见最上方应用题第五点
六、图
-
无向完全图:任意两个顶点之间都存在边,有n(n-1)/2条边
-
有向完全图:任意两个顶点之间都存在方向相反的两条弧,有**n(n-1)**条弧
-
顶点的度、入度和出度
-
度:依附于某个顶点的边的数目
-
无向图的全部顶点的度的和 等于 边数的两倍
-
有向图
- 入度是顶点v为终点的有向边的数目
- 出度是顶点v为起点的有向边的数目
- 顶点的度=入度+出度
- 有向图全部顶点的 入度之和=出度之和=边数
-
-
邻接矩阵表示法优点2:
-
无向图:邻接矩阵第i行元素之和是顶点vi的度
-
有向图:第i行元素之和是顶点vi的出度
第i列元素之和是顶点vi的入度
(i行和出度 i列和入度)
-
七、查找
-
折半查找的格式:折半查找要求线性表必须采用****顺序存储结构*,而且表中元素按关键字*有序排列****。(判断题)
-
散列表的装填因子:a****越小*,发生冲突的可能性*越小*; a*越大*,发生冲突的可能性*越大****。
a=表中填入的记录数/散列表的长度
-
散列查找与平均查找长度和记录总数 无关(判断、填空题)
-
顺序查找的平均查找长度:
ASL成功=(n+1)/2
-
采用线性探测法处理冲突,可能要探测多个位置,在查找成功的情况下,所探测的这些位置上的关键字不一定都是同义词
(所探测的这些关键字可能是在处理其它关键字冲突过程中放入该位置的)
八、排序
-
排序稳定性,记住希尔排序、快速排序、堆排序是不稳定排序,其它都是稳定排序。
-
散列查找与平均查找长度和记录总数 无关(判断、填空题)
-
顺序查找的平均查找长度:
ASL成功=(n+1)/2
-
采用线性探测法处理冲突,可能要探测多个位置,在查找成功的情况下,所探测的这些位置上的关键字不一定都是同义词
(所探测的这些关键字可能是在处理其它关键字冲突过程中放入该位置的)
八、排序
- 排序稳定性,记住希尔排序、快速排序、堆排序是不稳定排序,其它都是稳定排序。
补充
- 线性表采用链表作为存储结构时,通常会另外附加一个头结点,这样做的好处是 简化边界条件的处理