Algorithms + Data Structures = Programs
数据结构与算法 严蔚敏 王卓_哔哩哔哩_bilibili
一.导论
1.基本概念和术语
Data 数据
Data Element 数据元素
node节点
Data Ltem 数据项
Data Object数据对象
2数据结构 Data Structure
数据结构包括以下三个部分
- 数据结构之间的逻辑关系 也叫逻辑结构
- 数据元素关系在计算机内存中的表示 也叫数据结构的物理结构或者数据的存储结构
- 数据的运算和实现 即对数据结构元素可以施加操作也i及在对应存储结构的实现
逻辑结构
3.数据类型
一些基本的数据结构可以用数据类型实现,如数组字符串等
而另一些常用的数据结构如栈队列 树图不能直接用数据类型表示
抽象数据类型
可以用DSP三元组表示出来 D是数据对象 S是D上的关系集 P是对D的基本操作集
定义格式
1 2 3 4 5 6 7 8 9 10 11 12 13
| Abstract Data Type 抽象数据类型名{ 数据对象 数据关系 基本操作 }Abstract Data Type抽象数据名
基本操作定义格式为 基本操作名(参数表) 初始条件《初始条件描述》 操作结果《操作结果描述》
参数表:赋值参数 职位操作提供输入值 引入参数&打头 除可提供输入值外 还将返回操作结果
|
4算法
算法的设计和要求
正确性 可读性 健壮性 高效性(鲁棒性)
5.算法的分析
1.时间效率
算法的时间效率的度量
算法运行时间=每条语句频度语句执行一次时间
1 2 3 4 5 6 7 8 9
| n*n矩阵相乘的算法 for(i=1;i<=n,i++) for(j=1;j<=n;j++) c[i][j]=0; for(k=0;k<=n;k++) c[i][j]=c[i][j]+a[i][k]*b[k][j];
执行n*n*n T(n)为2n^3+3n^2+2n+1
|
比较算法比较我们仅仅比较数量级
T1(n)=10*n2和T2(n)=5n3 O 前者好
-
有一个辅助的f(n)使得当n无限大,T(N)/F(N)极限为不同为零的常熟
则称f(n)是t(n)的同数级函数 记作T(n)=O(f(n))
称O(f(n))为算法的渐进时间复杂度简称为时间复杂度
-
F(n)=nm+nm-1…则T(N)=o(N^M)
-
算法基本操作次数也和问题输入而不同
1 2 3 4 5 6 7 8 9 10
| 比如说 for(i=0;i<n,i++) if(a[i]==e)return i+1; return 0; 最好只有一次执行 最坏要执行n次 最坏时间复杂度:最坏情况下 最好时间复杂度:最好情况下 平均时间复杂度为O(n)
|
- 复杂的算法,可以分成几部分利用O的加乘法则
- 加法T(n)=T1(n)+T2(n)=O(f(n))+O(g(n))=O(max(f(n),g(n)))
- 乘法T(n)=T1(n)xT2(n)=O(f(n))xO(g(n))=O((f(n)xg(n))
2空间复杂度
算法所要的存储空间度量
S(n)=O(f(n))
n为为问题的规模
1 2 3 4 5 6 7 8 9 10 11 12
| 将一维数组a的n个数逆序放到元素组 for(i=0;i<n/2;i++){ t=a[i]; a[i]=a[n-i-1]; a[n-1-i]=t; }
for(i=0;i<n;i++) b[i]=a[n-1-i]; for(i=0;i<n;i++) a[i]=b[i];
|
二.线性表linear list
1线性表的定义和特点
例子
如26英文字母 数据元素都是字母为线性
线性表的逻辑特征
在非空中有且仅有一个开始或者终端的结点,他没有前趋而仅有一个后续a2 或者没有后趋,而仅有一个直接前趋an-1
案例引入
一元多项式
2.线性表的类型定义
基本操作
- lnitlist(&L)构造一个空的线性表L
- DestroyList(&L)初始条件线性表已经有了 操作结果摧毁线性表
- ClearList(&L)初始条件线性表存在了 操作结果重置为空表
- ListEmpty(L)初始条件 线性表存在 操作结果如果为空表为ture
- ListLength(L)初始条件 线性表存在 操作结果返回L中数据元素个数
- GetElem(L,i,&e)初始太久存在 操作结果用e返回L中第i哥元素值
- LocateElem(L,e,compare())初始线性表存在,compare是数据元素判定函数 操作结果返回L中第一个与e满足compare的数据元素的位序若这样的数据元素不存在返回0
- PriorElem(L,cur_e,&pre_e)初始为L存在 操作结果cur_e为L的元素,不是第一个,则pre_e返回他的前驱,否则操作失败 pre_e没有意义
- NextElem(L,cur_e,&next_e)初始L存在,如果cur存在返回后继
- Listinsert(&L,i,e)L存在 L在第i个位置之前插入新的元素e,L的长度加1
- ListDelete(&L,i,&e)L存在 删除L的第i个元素,用e返回,L减一。
- ListTraversr(&L,visited())L存在 操作结果依次对线性表中每个元素调用visited()
3.线性表的顺序表示和实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| typedef struct{ ElemType data[]; int length; }SqList;
SqList L; L.data=(ElemType*)malloc(sizeof(ElemTAype)*M)
#define LIST_INTI_SIZE 100 typedef struct { int elem[LIST_INTI_SIZE]; int length; }Sqlist;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #define MAXSIZE 1000 typedef struct { float p; int e; }Polynomial; typedef struct { Polynomial* elem; int length; }SqList;
#define MAXSIZE 1000 typedef struct { char no[20]; char name[50]; float price; }book; typedef struct { book* elem; int length; }SqList;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include "stdio.h" #include "stdlib.h" #include "math.h" #include "time.h" #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 //#define OVERFLOW -2 #define INFEASIBLE -1 #define MAXSIZE 20 typedef char ElemType; typedef int Status; typedef struct { ElemType *elem; int length; }SqList; //1.线性表的初始化 Status InitList_Sq(SqList* L) { //分配空间 L->elem = (ElemType*)malloc(sizeof(ElemType) * MAXSIZE); //L->elem = new ElemType[MAXSIZE]; C++写法 if (!L->elem)exit(OVERFLOW);//分配失败 L->length = 0; return OK;//空表长度为零 } //2.摧毁线性表L void DestroyList(SqList* L) { if (L->elem) free(L->elem);//delete L->elem;释放空间 } //3.清空线性表 void ClearList(SqList* L) { L->length = 0;//将线性表长度为0 } int GetLength(SqList* L) { return (L->length); } //4判断线性表为空 int IsEmpty(SqList L) { if (L.length == 0) return 1; else return 0; } //5顺序表的取值 int GetElem(SqList L, int i, ElemType& e) { if (i<1 || i>L.length) return ERROR; e = L.elem[i - 1]; return OK; } //6插入 Status Listlnsert_Sq(SqList* L, int i, ElemType e) { int j; if (i<1 || i>L->length + 1)return ERROR; if (L->length == MAXSIZE) return ERROR; for (j = L->length; j >= i - 1; j--) L->elem[j+1] = L->elem[j]; L->elem[i - 1] = e; L->length++; return OK; } //7删除 Status ListDelete_Sq(SqList* L, int i) { int j; if (i<1 || i>L->length) return ERROR; for (j = i; j <= L->length; j++) L->elem[j - 1] = L->elem[j]; L->length--; return OK; } int main() { SqList L; InitList_Sq(&L); GetLength(&L); }
|
优点
缺点
4线性表的链式
- 结点:数据元素的存储映像。由数据域和指针域
- 链表:N个结点由指针域组成链表 它是线性表的链式存储映像名称为线性表的链性存储
1.单链表
结点只有一个指针域的链表
特点
- 结点在存储器的位置是任意的,即逻辑上相邻的数据元素,在物理上不一定
- 访问时只能通过头指针进入链表,并通过每个结点的指针域依次向后,寻找第一个和最后一个结点
栈与队列
栈与队列是两个常用的
栈与队列是限定插入和删除只能在表的端点进行的线性表
1 2
| Insert(S,n+1,x) Delete(S,n) Insert(Q,n+1,x) Delete(Q,1)
|
- 栈–后进先出
使得栈成为有用的工具,数据转换,表达式,函数调用,递归,括号
解决排队问题 脱机打印 多用户系统 等
栈stack
特殊的线性表,是限定在一段,通常是表尾,进行插入和删除操作的线性表
相关概念
后进an top栈顶 表头a1为base
插入元素到栈顶叫入栈(压)push,反之为入栈(弹出)pop
栈的定义
- 定义:限定在表的一端进行插入和删除的运算线性表
- 逻辑结构:通线性表一对一的关系
- 存储结构:顺序表更常见
- 只能在栈顶运算
- 入栈和出栈函数
案例
进制转换
十进制N想其他进制数d(二八十六)
**法则为:**除以d倒取余
n=(n div d)*d + n mod d
div为整除运算 mod为求余
例子十进制159转八进制
1 2 3 4
| 159/8=19...7 19/8=2...3 2/8=0..2 (237)8
|
括号匹配的验证
表达式求值
操作数和运算符和界限符
为了实现表达式求值设置两个栈
OPTR寄存运算符 操作数栈OPND用于寄存运算数和运算结果
栈的表示和操作
1 2 3 4 5 6 7
| ADK Stack{ 数据对象D={ai|ai属于ElemSet} 数据关系R1={<ai-1,ai>} an端为栈顶,a1为栈底 初始化 进栈出栈 取栈顶等
}ADT Stack
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| InitStack(&S)初始化操作 构造一个空栈S DestoryStack(&S) 销毁栈操作 初始条件S存在,结果销毁
StackEmpty 判断是否为空 S存在 空true 否为false
StackLength(S)求栈的长度 S存在 返回S的个数,即栈长度
GetTop(S,&e)去栈顶 S存在且为空 用e返回S的栈顶元素
ClearStack清空
Push(&S,e)入栈
|
顺序栈的实现,同一般线性表的顺序存完全相同
1 2 3 4 5 6
| #define MAXSIZE 100 typedef struct{ SElemType *base; SElemType *top; int stacksize }Sqstack;
|
初始化
1 2 3 4 5 6 7
| Status InitStack(SqStack &S){ S.base=(SElemType*)malloc(MAXSIZE*sizeof(SElemType)); if(!S.base)exiu(OBERFLOW); S.top=S.base; S.stacksize=MAXSIZE; return OK; }
|
判断是否为空
1 2 3 4 5
| Status StackEmpty(SqStack S){ if(S.top==S.base)return TRUE; else return FALSE;
}
|
顺序栈长度
1 2 3
| int StackLength(SqStack S){ return S.top-S.base; }
|
清空
1 2 3 4
| Status ClearStack(Sqstack &S){ if(S.base)S,top=S.base; return OK; }
|
销毁
1 2 3 4 5 6 7 8
| Status DestroyStack(Sqstack &S){ if(S.base){ delete S.base; S.stacksize=; S.base=S.top=NULL; } return OK; }
|
入栈
1 2 3 4 5 6
| Status Push (SqStack &S,SElemType e){ if(S.top-S.base==S.stacksize)return ERROR; *S.top=e; S.top++; return OK; }
|
出栈
1 2 3 4 5
| Status Ppo(SqStack &S,SElemType&e){ if(S.top==S.base)return ERROEL; E=*--s.TOP; return OK; }
|
链栈
1 2 3 4 5 6
| typedef struct StackNode{ SElemType data; struct StackNode *next; }StackNode,*LinkStack;
LinkStack S;
|
链表的初始化
1 2 3 4
| void InitStack(LinkStack &S){ S=NULL; return ok; }
|
入栈
1 2 3 4 5 6 7
| Status Push(LinkStack &S,SElemType e){ p=new stacknoode; p->data=e; p->newt=S; S=p; return OK; }
|
出栈
1 2 3 4 5 6 7 8
| Status Pop(LinkStack&S,SElemTyoe &e){ if(S==NULL)return ERROE; e=s->data; p=S; S=S->next; delete p; }
|
栈与递归
递归定义的函数 递归数据结构 递归解法
队列queue
先进先出FiFO
表一插入,在另一端表头删除
队列的相关概念
- 定义 头删尾插
- 逻辑结构 一对一先信标
- 循环和链队
- 之恶能在对手和队尾
- 入和出 队
树
树的定义
Tree是由包括零,多个结点的有限集,分为空树
�限集,分为空树