数据结构基础

第一章 绪论

概念

1.数据:数据是信息的载体,是描述客观事物属性的数、符号以及所有能输入到计算机中并被计算机程序识别和处理的符号的集合
2.数据元素:是数据的基本单位。
3.数据项:是数据的最小单位。
4.数据对象:具有相同性质的数据元素集合。
5.数据类型:是一个值的集合和定义在此集合上的操作的总称。
1)原子类型:int,char,float等
2)结构类型:list,map,set等
3)抽象数据类型:所有可以抽象出的模型
6.抽象数据类型(ADT):数据对象,数据关系,基本操作集三元组来表示抽象数据类型。

三要素

1.逻辑结构:从逻辑关系上描述数据,和数据的存储无关,是独立于计算机的。
在这里插入图片描述
2.物理结构:即存储结构,是指数据结构在计算机中的表示。主要包括——顺序存储、链式存储、索引存储、散列存储。
3.运算:施加在数据上的运算包括运算的定义和实现。运算的定义是针对逻辑结构的,运算的实现是针对物理结构的。

算法

1.特征:有穷性、确定性、可行性、输入、输出。
2.度量
1)时间复杂度:T(n)=O(f(n))
例:某算法的时间复杂度为O(n2),表明该算法的执行时间与n2成正比。
2)空间复杂度:算法所耗费的存储空间。

第二章 线性表

定义与基本操作

1.定义:线性表是具有相同数据类型的n个元素的有限序列。
2.特点
1)个数有限
2)除了第一个元素外,每个元素都只有一个直接前驱
3)除了最后一个元素外,每个元素都只有一个直接后继
4)每个元素的数据类型相同
3.基本操作:
InitList(&L):初始化表。
Length(L):求表长。
LocateElem(L,e):按值查找。
GetElem(L,i):按位查找。
ListInsert(&L,i,e):插入。
ListDelete(&L,i,&e):删除。

顺序表

1.定义:线性表的顺序存储。
2.操作:
(1):插入
(2):删除
(3):查找

链表

1.单链表
(1)定义:线性表的链式存储。
(2)操作
<头插法>:
s→next=L→next
L→next=s
<尾插法>:

<按序查找>
<按值查找>
<插入>
<删除>
<求表长>
2.双链表
在这里插入图片描述

3.循环链表
(1)循环单链表
在这里插入图片描述

(2)循环双链表
在这里插入图片描述

4.静态链表

顺序表和链表的比较

1.存取方式:顺序表可以顺序存取也可以随机存取,链表只能顺序存取。
2.逻辑结构与物理结构:顺序表中,逻辑相邻的两个元素其物理存储位置也相邻;链表中,逻辑相邻的两个元素物理存储位置不一定相同。
3.查找、插入和删除:时间复杂度不同。

第三章 栈和队列

1.定义:只允许在一端插入或删除的线性表。
2.操作:
InitStack(&S):初始化栈。
Push(&S,x):进栈。
Pop(&S,x):出栈。
3.顺序栈
4.栈链

队列

1.定义:只允许在表的一端进行插入,而另一端进行删除。
2.顺序队列:
3.循环队列:
4链队列:
5双端队列:

应用

1.栈
1)括号匹配
2)表达式
3)递归
2.队列
1)层次遍历
2)计算机系统:解决主机与外部设备速度不匹配问题;解决多用户资源竞争问题。

第三章 树和二叉树

树的基本概念

1.定义:它是由n(n>=1)个有限结点组成一个具有层次关系的集合。

2.特点:每个结点有零个或多个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结点可以分为多个不相交的子树。
3.基本术语
1)双亲结点:A是B的双亲节点
2)孩子结点:B是A的孩子节点
3)兄弟结点:B和C是兄弟节点
4)结点的度:一个结点的子节点个数
5)树的度:结点的最大度数
6)分支结点:度大于0的节点,如D
7)叶子结点:度为0,如#
8)结点的层次:根结点为第一层
结点的深度:从根结点开始自顶向下累加
结点的高度:从叶子结点开始自底向上累加
9)路径:两个结点的路径是由这两个结点之间所经过的结点序列构成的
路径长度:是路径上经过的边的个数,如A和D的路径长度是2

二叉树

1.定义:每个结点至多只有两棵子树(任意节点的度不能大于2),并且二叉树有左右之分。
2.几种特殊的二叉树
(1)满二叉树:树中的每一层都含有最多的结点
在这里插入图片描述
(2)完全二叉树:最后一层有可能不满,从右往左的缺
在这里插入图片描述
(3)二叉排序树:左子树所有结点的关键字均小于根结点的关键字,右子树所有结点的关键字均大于根结点的关键字,左子树和右子树又各是一棵二叉排序树。
在这里插入图片描述
(4)二叉平衡树:树上任何结点的左子树和右子树的深度之差不超过1
在这里插入图片描述
如图,左边的是二叉平衡树,右边的不是
3.性质
1)非空二叉树上,叶子结点数=度为2的结点数+1
2)非空二叉树上,第K层上至多2k-1个结点
3)高度为H的二叉树最多有2H-1个结点

二叉树的遍历

1.先序遍历:根左右
2.中序遍历:左根右
3.后序遍历:左右根

树、森林

1.树、森林与二叉树的转换
(1)树转化为二叉树:每个结点的左指针指向它的第一个孩子节点,右指针指向相邻兄弟节点(垂直左孩子,水平右孩子)
在这里插入图片描述
(2)二叉树转化为树
在这里插入图片描述
(3)二叉树转化为森林:断右连线成森林,再把每棵二叉树转化为树
在这里插入图片描述
2.树的遍历
(1)先根遍历:与这棵树相应二叉树的先序遍历顺序相同
(2)后根遍历:与这棵树相应二叉树的中序遍历顺序相同
3.森林的遍历
(1)先序遍历:与这棵树相应二叉树的先序遍历顺序相同
(2)中序遍历:与这棵树相应二叉树的中序遍历顺序相同

树和二叉树的应用

1.二叉排序树:左子树所有结点的关键字均小于根节点的关键字,右子树所有结点的关键字均大于根结点的关键字,左子树和右子树又各是一棵二叉排序树。
对二叉排序树中序遍历,得到的是一个递增的序列。
2.平衡二叉树
(1)平衡因子:左子树与右子树的高度差。
(2)平衡二叉树的插入:
<1>LL
在这里插入图片描述
在这里插入图片描述
<2>RR
在这里插入图片描述
在这里插入图片描述

<3>LR
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<4>RL
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注:根和子树先调子树
3.哈夫曼树
(1)权:树的结点常常被赋予一个有意义的数字
(2)结点的带权路径长度:该结点到根结点的边数和该结点的权值之积
(3)WPL:树的带权路径长度,即树中所有叶结点的带权路径长度之和
(4)哈夫曼树:WPL最小的二叉树,也称最优二叉树
(5)构造哈夫曼树:权值越小的结点到根结点的路径长度越大
(6)应用:压缩

第五章 图

图的基本概念

1.基本定义:图G由顶点V和边E组成。|V|表示图的顶点个数,也叫做
2.有向图:当E是有向边,也叫时,G时有向图。
3.无向图:当E是无向边,也叫时,G时无向图。
4.简单图:该图满足,不存在重复的边且不存在顶点到自身的边。数据结构仅讨论简单图。
5.完全图:任意两个顶点之间都存在边。
6.顶点的度,入度和出度:顶点的度是指和该顶点相连的边的条数。特别是对于有向图来说,顶点的出边条数称为该顶点的出度,顶点的入边条数称为该顶点的入度。
在这里插入图片描述

图的存储

1.邻接矩阵法(顺序)
在这里插入图片描述
2.邻接表法(链式)
(1)无向图
在这里插入图片描述
(2)有向图
在这里插入图片描述
3.邻接矩阵和邻接表的优缺点

图的遍历

1.广度优先搜索(Breadth-First Search,BFS):和二叉树的层序遍历一致。

2.深度优先搜索(Depth First Search,DFS):一直往下访问,到底再返回到上一个结点
在这里插入图片描述

图的应用

1.最小生成树:权值之和最小的生成树。
(1)普利姆算法(prim):在这里插入图片描述

(2)克鲁斯卡尔算法(Kruskal):
在这里插入图片描述
2.最短路径:带权路径长度最短的路径
(1)迪杰斯特拉(Dijkstra)算法:
在这里插入图片描述
(2)Floyd算法
3.拓扑排序:
在这里插入图片描述

4.关键路径:
(1)源点:网中仅有一个入度为0的顶点,即源点。
(2)汇点:网中仅有一个出度为0的顶点,即汇点。
(3)关键路径:从源点到汇点的所有路径中,具有最大路径长度的路径称为关键路径。完成工程的最短时间就是关键路径的长度。

第六章 查找

第七章 排序

1.冒泡排序(交换排序算法)
(1)实现原理
从最后一个关键字开始,两两比较相邻记录的关键字,如果反序(前者大于后者)则交换,直到没有反序的记录为止,即完成一次冒泡排序,然后再依次进行相同操作,最多需 (length-1)次 冒泡排序。实质上,冒泡排序就是每次交换的结果作为下一次两两比较的基础,最终将较小的数字如同气泡般慢慢浮到上面。

(2)算法实现

void BubbleSort(int *a,int len){
    int temp = 0;
    /*第一步:边界处理,指针变量指向null,len<0*/
     if(!a||len<0)
          return;
    /*第二步:进行n-1次冒泡排序*/
    for(int i=0;i<len-1;i++){
    /*第三步:将最后一个元素开始依次与前len-i个元素比较,反序交换*/
        for(int j=len;j>i;j--){
            if(a[j-1]>a[j]){        //完成一次交换,将较小的存放到前面
                temp = a[j-1];
                a[j-1] = a[j];
                a[j] = temp;
            }
        }
    }
}

(3)算法性能分析
①时间复杂度:
◆最好情况:待排序本身有序,只需进行(n-1)次比较,没有数据移动,时间复杂度为O(n)
◆最坏情况:待排序逆序,需进行1+2+3+…+(n-1)=n*(n-1)/2数据移动,时间复
杂度为O(n^2)
②空间复杂度:冒泡算法只需要一个记录的辅助空间(temp),故空间复杂度为O(1).
③稳定性:没有跳跃式数据交换,稳定。
2.简单选择排序
(1)实现原理
对长度为n的序列,通过(n-i)次关键字间的比较,从(n-i+1)个记录中选出关键字最小的关键字,并与第i(1≤i≤n)个记录交换。举例:有一长度n=5的序列,初始状态为{57 68 59 52 49}
首先,取第一个记录57(i=1),通过n-i=4次比较,选出n-i+1=5个记录中最小关键字记录49,与第i=1交换;
在这里插入图片描述
其次,取第二个记录68(i=2),通过n-i=3次比较,选出n-i+1个记录中最小关键字记录52,与第i=2交换;
在这里插入图片描述
以此类推,最后得到的排序序列为:49 52 57 59 68
(2)算法实现

void selectSort(int *a,int len)
{
     int min,temp=0;
    /*第一步:边界处理,指针变量指向null,len<0*/
    if(!a||len<0)
         return;
     /*第二步:将第i个元素,与其他(n-i)个元素进行 比较,从(n-i+1)个元素中选出最小的并与第i个
        元素 进行交换。注意:第i个元素的下标为i-1(i>0)*/ 
     for(int i=0;i<len;i++){
          min=i;                                 //初始化min
          for(int j=i+1;j<len;j++){         //从第i+1个元素开始比较
                   if(a[min]>a[j])             //将(n-i+1)个元素中最小元素下标赋值给min
            min=j;
      }
      /*第三步:完成一次选择排序,将小标min对应最小元素与第i个元素互换*/
      if(i!=min){
           temp=a[i];
           a[i]=a[min];
           a[min]=temp;
      }
   }
}

(3)算法性能分析
①简单选择排序最大的特点就是交换移动数据的次数相当少,最好情况交换次数为0次,最坏情况(逆序)交换次数为n-1次。对于比较次数,最好最坏的情况都是一样多,因为第i趟排序需要进行n-1次关键字的比较,因此总共需要(n-1)+(n-2)+…+1=n(n-1)/2次比较。故总的时间复杂度=(n-1)+n(n-1)/2----->即O(n^2)。
②空间复杂度:冒泡算法只需要一个记录的辅助空间(temp),故空间复杂度为O(1).
③稳定性:没有跳跃式数据交换,稳定。
3.直接插入排序
(1)实现原理
将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增1的有序表。
★举例:序列的初始状态{57,68,59,52}
第一步:插入57到空表,此时,有序表为{57};
第二步:插入68到有序表,68>57,插在57之后,此时有序表为{57,68}
第三步:插入59到有序表,57<59<68,插在57和68之间,此时有序表为{57,59,68}
第四步:插入52到有序表,52<57,插在57之前,此时有序表为{52,57,59,68}
即,直接插入排序的结果为:52 57 59 68
(2)算法实现

//直接插入排序函数
void InsertSort(int *a,int len){
     int i,j,temp=0;	//temp辅助空间
     for(i=1;i<len;i++){	//第一个元素(下标为0)自然有序,从第二个元素开始排序
          if(a[i-1]>a[i]){	//由于第i个元素前面的元素已经有序,因此只需比较与第i-1个元素决定是否继续向前比较
               temp = a[i];	//将要排序的元素存放到临时变量中
               for(j=i-1;a[j]>temp;j--){	//后移逆序的元素
                a[j+1] = a[j];	//将元素依次向后移动一位
           }
           a[j+1]=temp;
      }
   }
}

(3)算法性能分析
①时间复杂度:
◆最好情况:序列本身有序,比较次数=n-1,移动次数为0,总次数=n-1+0
故时间复杂度为O(n);
◆最坏情况:序列逆序,比较次数=2+3+…+n=(n+2)(n+1)/2,移动次数=(n+4)(n-1)/2
故时间复杂度为O(n^2);
◆平均情况:O(n^2)
注:由于第i位元素的前i-1个元素有序,因此对于待排序的第i位元素只需与第i-1位元素比较即可
②空间复杂度:直接插入算法只需要一个记录的辅助空间,故空间复杂度为O(1).
③稳定性:是一种稳定的排序算法
4.快速排序(交换排序算法)
(1)实现原理
快速排序是冒泡排序的改进,快速排序也是分治法思想的一种实现,他的思路是:选取一个基准值,使数组中的每个元素与基准值(Pivot,通常是数组的首个值,A[0])比较,数组中比基准值小的放在基准值的左边,形成左部;比基准值Pivot大的放在右边,形成右部;当所有元素都比较完后,即说明完成一趟快速排序,此时,将待排序序列分割成独立的两部分,其中一部分的记录关键字均比另一部分记录的关键字小。再分别对这两个子序列进行快速排序,直到整个序列有序为止。
在这里插入图片描述
注意:比较(交换)后,若指针p2在基准的左边,则p2+1指向下一个元素;若指针p2在基本的右边,则p2-1指向下一个元素。
(2)算法性能分析
快速排序的时间取决于快速排序递归的深度,可以用递归树(为平衡树,性能较好)来描述递归算法的执行情况。
①时间复杂度:O(nlogn),O(nlogn),最坏情况O(n^2):

②空间复杂度:递归造成的栈空间的使用
最好情况,递归树的深度为log2^n,其空间复杂度为O(logn);
最坏情况,需要进行n-1递归调用,其空间复杂度为O(n);
③算法稳定性:由于关键字的比较和交换是跳跃式进行的,快速排序是不稳定的排序方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值