用于自己学习
第一节
感谢青岛大学王卓老师,属于很基础内容
怎么学好这门课程?
1.勤于思考
2.多做练习
3.多上机
4.善于寻求帮助
5.不怕困难,不放弃!!确实对初学者确实很难。
第二节
数据结构是一门研究非数值计算的程序设计中计算机的操作对象以及它们之间的关系和操作的学科。
第三节
数据:
数据元素:数据的基本单位,也称记录,结点或者顶点。
数据项:构成数据元素的不可分割的最小单位。
数据对象:性质相同的数据元素的集合,是数据的子集。
数据结构:数据元素不是孤立的,它们之间存在着某种关系,数据元素相互之间的关系称为结构。是指相互之间一种或者多种特定关系的数据元素的集合。
数据结构包括三个方面:逻辑结构,数据的存储结构,数据的运算和实现。
逻辑结构的种类:线性结构,非线性结构
存储结构:顺序存储结构,链式存储结构,索引存储结构,散列存储结构。
数据类型:数据类型时一组性质相同的值的集合以及定义于这个值集合的一组操作的总称。
抽象数据类型(A,D,T):是指一个数学模型以及定义在此数学模型上的一组操作。
抽象数据类型可以用(D,S,P)三元组表示
其中:D是数据对象
S是D上的关系集;
P是对D的基本操作集。
抽象数据类型的定义
ADT Cirle{
数据对象:D={r,x,y|r,x,y均为实数}
数据关系:R={<r,x,y>|r是半径,<x,y>是圆心坐标}
基本操作:
Circle(&C,r,x,y)
操作结果:构造一个圆。
double Area(C)
初始条件:圆已存在。
操作结果:计算面积。
double Circumference(C)
初始条件:圆已存在。
操作结果:计算周长。
......
}ADT Circle
第二章线性表
线性表具有相同特性的数据元素的有限序列。
同一线性表的元素必定具有相同特性,数据元素间的关系是线性关系。
InitList(&L):操作结果:构造一个空的线性表L
DestroyList(&L):初始条件:线性表L已经存在。操作结果:销毁线性表L。
ClearList(&L):初始条件:线性表L已存在。操作结果:将线性表L重置为空表。
ListEmpty(L):初始条件:线性表L已存在。操作结果:若线性表L为空,返回TURE,否则返回FALSE。
ListLength(L):初始条件:线性表L已存在。操作结果:返回线性表L中的数据元素个数。
GetElem(L,i,&e):初始条件:线性表L已存在,1<=i<=ListLength(L)。操作结果:用e返回线性表L中第i个数据元素的值。
LocateElem(L,e,compare()):初始条件:线性表L已存在,compare()是数据元素判定函数。操作结果:返回L中第1个与e满足compare()的数据元素的位序。若这样的数据元素不存在则返回值为0.
PriorElem(L,cur_e,&pre_e):初始条件:线性表L已存在。操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,否则操作失败;pre_e无意义。
NextElem(L,cur_e,&next_e):初始条件:线性表L已存在。操作结果:若cue_e是L的数据元素,且不是最后一个,则用next_e返回它的后继,否则操作失败,next_e无意义。
ListInsert(&L,i,e) :初始条件:线性表L已存在,1<=i<=ListLength(L)+1。操作结果:在L的第i个位置之前插入新的数据元素e,L的长度加一。
ListDelete(&L,i,&e);初始条件:线性表L已存在,1<=i<=ListLength(L)。操作结果:删除L的第i个数据元素,并用e返回其值,L的长度减一。
ListTraverse(&L,visited()):初始条件:线性表L已存在。操作结果:依次对线性表中的每个元素调用visited()。
线性表有两种基本的存储结构:顺序存储结构和链式存储结构
顺序存储:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构。
#define LIST_INIT_SIZE 100
typedef struct{
ElemType elem[LIST_INIT_SIZE];
int length;
}SqList;
typedef struct{
float p;
int e;
}polynomial;
typedef struct{
polynomial *elem;
int length;
}SqList;
数组的静态分配和数组的动态分配
typedef struct{
ElemType data[MaxSize];
int length;
}SqList;//顺序表类型
typedef struct{
ElemType *data;
int length;
}SqList;//顺序表类型
SqList L;
l.data=(ElemType*)malloc(sizeof(ElemType)*MaxSize);//需要加载头文件:
malloc(m)函数,开辟m字节长度的地址空间,并返回这段空间的首地址
sizeof(x)运算,计算变量x的长度
free(p),释放指针p所指向变量的存储空间,即彻底删除一个变量
C++的动态存储分配
int *p1=new int;或 int *p1=new int(10);
delete p1;
c++中的参数传递
参数传递有两种方式:传值方式(参数为整型,实型,字符型等)
传地址:参数为指针变量,参数为引用类型,参数为数组名
函数结果状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
//Status是函数的类型,其值是函数结果状态代码
typedef int Status;
typedef char ElemType;
顺序表基本操作的实现
线性表L初始化(参数用引用)
Status Initlist_Sq(SqList&L){//构造一个空的顺序表L
L.elem=new ElemType[MAXSIZE];//为顺序表分配空间
if(!L.elem) exit(OVERFLOW);//存储空间分配失败
L.length=0;//空表长度为0
return OK;
}
销毁线性表L
void DestroryList(SqList&L){
if(L.elem) delete L.elem;//释放存储空间
}
清空线性表L
void ClearList(SqList&L){
L.length=0;//将线性表的长度置为0
}
求线性表L长度
int GetLength(SqList L){
return (L.length);
}
判断线性表L是否为空
int IsEmpty(SqList L){
if(L.length==0)return 1;
else return 0;
}
顺序表取值(随机存取)
int GetElem(SqList L,int i,ElemType &e){
if(i<1||i>L.length)return ERROR;
e=L.elem[i-1];
return OK;
}
顺序表的查找操作
按值查找:在线性表L中查找与指定值e相同的数据元素的位置,从前往后找。
int LocateElem(SqList L,ElemType e){
//在线性表L中查找值为e的数据元素,返回其序号(是第几个元素)
for(i=0;i<L.length;i++)
if(L.elem[i]==e)return i+1;
return 0;
}顺序查找的平均查找长度:ASL=(n+1)/2
平均查找长度ASL:为确定记录在表中的位置,需要与给定值进行比较的关键字的个数的期望叫做查找算法的平均查找长度。
顺序表的插入
插入位置在最后
插入位置在中间
插入位置在最前面
Status ListInsert_Sq(SqList&L,int i,ElemType e){
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;
}//算法的平均时间复杂度n/2即O(n)
顺序表的删除
删除算法演示:
删除位置在最后
删除位置在中间
删除位置在最前面
Status ListDelete_Sq(SqList&L,int i){
if(i<1||i>length())return ERROR;
for(j=i;j<=L.length-1;j++)
L.elem[j-1]=L.elem[j];
L.length--;
return OK;
}//算法时间复杂度:(n-1)/2即O(n)
线性表的链式存储顺序存取
结点:数据元素的存储映像,由数据域和指针域两部分组成
链表:n个结点由指针链组成一个链表。
单链表:结点只有一个指针域
双链表:结点有两个指针域
循环链表:首尾相连的链表
头指针:是指向链表中第一个结点的指针
首元结点:是指链表中存储第一个数据元素的结点
头节点:是在链表首元结点之前附设的一个节点
单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名,若头指针名是L,则把链表称为表L。
typedef struct Lnode{
ElemType data;
struct Lnode *next;
}LNode,*LinkList;//LNode结构体,LinkList为指向结构体Lnode的指针类型
定义链表L: LinkList L;
定义结点指针P:Lnode*p ;
例如:
typedef struct student{
char num[8];
char name[8];
int score;
struct student *next;
}Lnode,*LinkList;
为了统一链表操作,通常这样定义:
typedef struct{
char num[8];
char name[8];
int score;
}ElemType;
typedef struct Lnode{
ElemType data;
struct Lnode *next;
}Lnode,*LinkList;
单链表的初始化
status InitList L(LinkList &L){
L=new LNode;//或L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
return OK;
}
判断链表是否为空
int ListEmpty(LinkList L){
if(L->next==NULL)
return 1;
else
return 0;
}
单链表的销毁:链表销毁后不存在
从头结点开始,依次删除所有节点。
status DestroyList_L(ListList &L){
Lnode *p;
while(L){
p=L;
L=L->next;
delete p;
}
return OK;
}
清空单链表:链表仍存在,但无元素。
status ClearList(LinkList &L){
Lnode *p,*q;
p=L->next;
while(p){
q=p->next;
delete p;
p=q;
}
L-next=NULL;
return OK;
}
求单链表的表长
int ListLength_L(LinkList L){
LinkList p;
p=L->next;
i=0;
while(p){
i++;
p=p->next;
}
return i;
}
取值:取单链表中第i个元素的内容
status GetElem_L(LinkList L,int i,ElemType &e){//获取线性表L中的某个数据元素的内容,通过变量e返回
p=L->next;j=1;
while(p&&j<i){//向后扫描,直到p指向第i个元素或p为空
p=p->next;++j;
}
if(!p||j>i)return ERROR;
e=p->data;
return Ok;
}
查找:按值查找
Lnode *LocateElem_L(LinkList L,Elemtype e){
//在线性表L中查找值为e的数据元素
//找到,返回L中e的**地址**,查找失败返回NULL
p=L->next;
while(p&&p->data!=e)
p=p->next;
return p;
}
int LocateElem_L(LinkList L,Elemtype e){
//在线性表L中查找值为e的数据元素的**位置序号**
//找到,返回L中e的数据元素的**位置序号**,查找失败返回0
p=L->next;j=1;
while(p&&p->data!=e)
{p=p->next;j++;}
if(p)return j;
else return 0;
插入节点:
status ListInsert_L(LinkList &L,int i,ElemType e){
p=L;j=0;
while(p&&j<i-1){p=p->next;++j;}//寻找第i-1个结点,p指向i-1结点
if(!p||j>i-1)return ERROR;i大于表长或者小于1,插入位置非法
s=new LNode;s->date=e;
s->next=p->next;//将结点s插入L中
p->next=s;
return OK;
}
删除第i个结点操作
status ListDelete_L(LinkList &L,int i,ElemType &e){
p=L;j=0;
while(p->next&&j<i-1){p=p->next;++j;}//寻找第i个结点,并令p指向其前驱
if((!p->next)||j>i-1)return ERROR;
q=p->next;
p->next=q->next;
e=q->data;
delete q;
return OK;
}
头插法建立单链表:头插法—元素插入在链表头部,也叫前插法
void CreateList_H(LinkList &L,int n){
L=new LNode;
L->next=NULL;
for(i=n;i>0;--i){
p=new LNode;
cin>>p-data;
p->next=L->next;
L->next=p;
}
}//CreateList_H
尾插法—元素插入在链表尾部,也叫后插法(需要加一个尾指针)
void CreateList_R(LinkList &L,int n){
L=new LNode;L->next=NULL;
r=L;//尾指针r指向头结点
for(i=0;i<n;i++){
p=new LNode;cin>>p->data;
p->next=NULL;
r->next=p;//插入到表尾
r=p;//r指向新的尾结点
}
}CreateList_R
循环链表:是一种头尾相连的链表(即:表中最后一个结点的指针域指向头节点,整个链表形成一个环)
优点:从表中的任意节点出发均可找到表中其他节点。
由于循环链表中没有NULL指针,其涉及遍历操作时,判断它们是否等于头指针
带尾指针循环链表的合并
LinkList Connect(LinkList Ta,LinkList Tb){//假设TaTb都是非空的单循环链表
p=Ta->next;//p存表头结点
Ta->next=Tb->next->next;//Tb表头连接Ta表尾
delete Tb->next;//释放Tb表头结点
Tb->next=p;//修改指针
return Tb;
}
双向链表
双向链表的结构可定义为
typedef struct DuLNode{
Elemtype data;
struct DuLNode *prior,*next;
}DuLNode,*DuLinkList;
双向链表的插入
void ListInsert_DuL(DuLinkList &L,int i,ElemType e){
//在带头节点的双向循环链表L中插入第i个位置之前插入元素e
if(!(p=GetElemP_DUl(L,i)))return ERROR;
s=new DuLNode;s->data=e;
s->prior=p->prior;p->prior->next=s;
s->next=p;p->prior=s;
return OK;
}
双向链表的删除
void ListDelete_DuL(DuLinkList &L,int i,ElemType e){
//删除带头节点的双向循环链表L中第i个元素,并用e返回
if(!(p=GetElemP_DUl(L,i))) return ERROR;
e=p->data;
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
return OK;
}
线性表的合并
void union(List %La,List Lb){
La_Len=ListLength(La);
Lb_len=ListLength(Lb);
for(i=1;i<=Lb_len;i++){
GetElem(Lb,i,e);
if(!LocateElem(La,e)) ListInsert(&La,++La_len,e);
}
}
有序表的合并—用顺序表实现
void MergeList_Sq(SqList LA,SqList LB,SqList&LC){
pa=LA.elem;
pb=LB.elem;//指针pa,pb的初值分别指向两个表的第一个元素
LC.length=LA.length+LB.length;//新表长度
LC.elem=new ElemType[LC.length];//为合并后的新表分配数组空间
pc=LC.elem;//指针pc指向新表的第一个元素
pa_last=LA.elem+LA.length-1;//指向LA表的最后一个元素
pb_last=LB.elem+LB.length-1;//指向LB表的最后一个元素
while(pa<=pa_last&&pb<=pb_last){
if(*pa<=*pb)*pc++=*pa++;//依次取两表中,值较小的结点
else *pc++=*pb++;
}
while(pa<=pa_last) *pc++=*pa++;//LB到达末尾,将LA中剩余元素加入LC
while(pb<=pb_last) *pc++=*pb++;//
}//MerList_Sq
有序表的合并—用链表实现
void MergeList(LinkList &La,LinkList &Lb,LinkList &Lc){
pa=La->next;pb=Lb->next;
pc=Lc=La;//用La的头节点作为LC的头节点
while(pa&&pb){
if(pa->data<=pb->data){pc->next=pa;pc=pa;pa=pa->next;}
else{pc->next=pb;pc=pb;pb=pb->next;}
}
pc->next=pa?pa:pb;//插入剩余段
delete Lb;//释放Lb的头节点
}
案列分析与实现
两个一元多项式的运算
稀疏多项式的运算
栈是一个特殊的线性表,是限定仅在一端进行插入和删除操作的线性表。后进先出,简称(LIFO)
栈仅在表尾进行插入和删除,表尾称为栈顶Top,表头称为栈底Base,入栈push,出栈pop
队列是一种先进先出的线性表,在表尾插入,表头删除
案列引入:进制转换,括号匹配检验,表达式求值,舞伴案例。
栈的基本操作
InitStack(&S):初始化操作,操作结果:构造一个空栈S
DestroyStack(&S):销毁栈操作。
StackEmpty(S):判断S是否为空,空返回TRUE,否则FALSE
StackLength(S):求栈的长度,返回S的元素个数
GetTop(S,&e):取栈顶元素,用e返回
ClearStack(&S):把栈清空
Push(&S,e):压栈,插入元素e为新的栈顶元素
Pop(&S,&e):删除S的栈顶元素,并用e返回其值
顺序栈的表示和实现
为了真正的方便操作,通常top指示真正的栈顶元素之上的下标地址
另外,用stacksize来表示栈可使用的最大容量
空栈:basetop
栈满:top-basestacksize
栈满的处理方法:1.报错返回操作系统。2.分配更大的空间,作为栈的存储空间,将原栈的内容移入新栈。
顺序栈的表示:
#define MAXSIZE 100
typedef struct{
SElemType *base;//栈顶指针
SElemType *top;//栈底指针
int stacksize;//栈可用的最大容量
}SqStack;
顺序栈的初始化
status InitStack(SqStack &S){//构造一个空栈
s.base=new SElemtype[MAXSIZE];
if(S.base)exit(OVERFLOW);//存储分配失败
S.top=S.base;//栈顶指针等于栈底指针
S.stacksize=MAXSIZE;
return OK;
}
顺序栈判断是否为空
status StackEempty(SqStack S){
if(S.top==S.base)
return TURE;
else
return FALSE;
}
求栈的长度
int StackLength(SqStack S){
return S.top-S.base;
}
清空顺序栈
status ClearStack(SqStack S){
if(S.base)S.top=S.base;
return OK;
}
销毁顺序栈
status DestoryStack(SqStack &S){
if(S.base){
delete S.base;
S.stacksize=0;
S.base=S.top=NULL;
}
return OK;
}
顺序栈的入栈
status Push(SqStack &S,SElemType e){
if(S.top-S.base==S.stacksize)//栈满
return ERROR;
*S.top++=e;//*S.top=e;S.top++;
return OK;
}
顺序栈的出栈
status Pop(SqStack &S,SElemType &e){
if(S.top==S.base)
return EEROR;
e=*--S.top;//--S.top;e=*S.top;
return OK;
}
链栈的表示
链栈时运算受限的单链表,只能在链表头部进行操作,链表的头指针就是栈顶,不需要头节点,基本不存在栈满的情况,空栈相当于头指针指向空,插入和删除仅在栈顶处执行。
typedef struct StackNode{
SElemType data;
struct StackNode*next;
}StackNode,*LinkStack;
LinkStack S;
链栈的初始化
void InitStack(LinkStack &S){
S=NULL;
return OK;
}
判断链栈是否为空
status StackEmpty(LinkStack S){
if(S=NULL)return TURE;
else return FALSE;
}
链栈的入栈和出栈
status Push(LinkStack &S,SElemType e){
p=new StackNode;//生成新节点
p->data=e;//将新节点数据域置为e
p->next=S;将新节点插入栈顶
S=p;//修改栈顶指针
return OK;
}
status Pop(LinkStack &S,SElemType &e){
if(S=NULL)return ERROR
e=S->data;
p=S;
S=S->next;
delete p;
return OK;
}
取栈顶元素
SElemType GetTop(LinkStack S){
if(S!=NULL)
return S->data;
}
栈和递归
队列的表示与操作的实现
队列的存储结构为链队和顺序队(常用循环队)
队列的顺序表示
#define MAXQSIZE 100
Typedef struct{
QElemType *base;//初始化的动态分配存储空间
int front;//头指针
int rear;//尾指针
}SqQueue;
解决假上溢问题,引入循环队列
base[0]接在base[MAXQSIZE-1]之后,若rear+1==M,则令rear=0;
实现方法:利用模(mod,c语言:%)运算
插入元素:Q.base[Q.rear]=x;Q.rear=(Q.rear+1)%MAXQSIZE;
删除元素:x=Q.base[s.front];Q.front=(Q.front+1)%MAXSIZE;
队空:frontrear
队满:(rear+1)%MAXQSIZEfront
循环队列的操作—队列的初始化
status InitQueue(SqQueue &Q){
Q.base=new QElemType[MAXQSIZE]//分配数组空间
if(!Q.base)exit(OVERFLOW);
Q.front=Q.rear=0;//头指针指针置为零,队列为空
return OK;
}
循环队列的操作—求队列的长度
int QueueLength(SqQueue Q){
return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}
循环队列的入队和出队
status EnQueue(SqQueue &Q,QElemType e){
if((Q.rear+1)%MAXQSIZRE==Q.front) return ERROR;//队满
Q.base[Q.rear]=e;//新元素加入队尾
Q.rear=(Q.rear+1)%MAXQSIZE;//队尾指针+1
return OK;
}
status DeQueue(SqQueue &Q,QElemType &e){
if(Q.rear==Q.front) return ERROR;//队空
e=Q.base[Q.front];//保存队头元素
Q.front=(Q.front+1)%MAXSIZE;//对头指针加一
return OK;
循环队列的操作—取对头元素
SElemType GetHead(SqQueue Q){
if(Q.front=Q.rear)
return Q.base[Q.front];
}
链队–链队的类型定义
#define MAXQSIZE 100
typedef struct Qnode{
QElemType data;
struct Qnode *next;
}QNode,*Queneptr;
typedef struct{
QuenePtr front;//队头指针
QuenePtr rear;//队尾指针
}LinkQueue;
链队列的初始化
status InitQueue(LinkQueue &Q){
Q.front=Q.rear=(QueuePtr)malloc(size(Qnode));
if(!Q.front)exit(OVERFLOE);
Q.front->next=NULL;
return OK;
}
链队列的销毁
status DestroyQueue(LinkQueue &Q){
while(Q.front){
p=Q.front->next;free(Q.front);Q.front=p;
}
return OK;
}
链队列的操作将元素e入队
status EnQueue(LinkQueue &Q,QElemType e){
p=(QueuePtr)malloc(size(Qnode));
if(!p)exit(OVERFLOW);
p->data=e;p->next=NULL;
Q.rear->next=p;
Q.rear=p;
return OK;
}
链队列的出队
status DeQueue(LinkQueue &Q,QElemType &e){
if(Q.front==Q.rear)return ERROR;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear==p) Q.rear=Q.front;
delete p;
return OK;
}
求链队列头节点的对头元素
status GetHead(LinkQueue Q,QElemType &e){
if(Q.front==Q.rear) return ERROR;
e=Q.front->next->data;
return OK;
}
串:零个或多个任意字符组成的有限序列。
子串:一个串中任意个连续字符组成的子序列(含空串)称为该串的子串。
串的类型定义,存储结构及运算
ADT 串(string)
data
串中元素仅由一个字符组成,相邻元素具有前驱和后继的关系
operation
StrAssign(T,*chars):生成其值等于字符串常量chars的串T。
StrCopy(T,S):串S存在,由串S赋值的串T。
ClearString(S):串S存在,将串清空。
StringEmpty(S):若S为空则返回ture,否则返回false。
StrLength(S):返回串S的元素个数,即串的长度。
StrCmpare(S,T):若S>T,返回值>0,若S=T,若S
串的顺序存储结构
#define MAXLEN 255
typedef struct{
char ch[MAXLEN+1];//存储串的一维数组
int length;
}SString;
串的链式存储结构–块链结构
#define CHUNKSIZE 80//块的大小由用户定义
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk *next;
}Chunk;
typedef struct{
Chunk *head,*tail;//串的头指针和尾指针
int curlen;//串当前长度
}LString;//字符串的块链结构
串的模式匹配算法
确定主串中所含子串(模式串)第一次出现的位置(定位)
BF算法,简单匹配算法,采用穷举法的思路。
算法思路从S的每一个字符开始依次与T的字符进行匹配。
Index(S,T,pos)
将主串的第pos个字符与模式串的第一个字符比较,
若相等,继续逐个比较后续字符;
若不等,从主串的下一个字符起,重新与模式串的第一个字符比较。
直到主串的一个连续子串字符序列与模式串相等,返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功,否则匹配失败,返回零。
int Index BF(SString S,SString T,int pos){
int i=pos;j=1;
while(i<=S.length &&j<=T.length){
if(S.ch[i]==T.ch[j]){++i;++j;}//主串与字串依次匹配下一个字符
else {i=i-j+2;j=1;}//主串,子串指针回溯重新开始下一次匹配
}
if(j>T.length)return i-T.length;//返回匹配的第一个字符的下标
else return 0;//模式匹配不成功
}
算法复杂度:O(n*m)/2
KMP算法:O(n+m)
int Index kmp(SString S,SString T,int pos){
int i=pos;j=1;
while(i<=S.length &&j<=T.length){
if(j==0||S.ch[i]==T.ch[j]){++i;++j;}
else
j=next[j];//i不变,j后退
}
if(j>T.length)return i-T.length;//匹配成功
else return 0;//匹配不成功
}
void get_next(SString T,int &next[]){
i=1;next[1]=0;j=0;
while(i<T.length){
if(j==0||T.ch[i]==T.ch[j]){
++i;++j;
next[i]=j;
}
else
j=next[j];
}
}
为此,定义next[j]函数,表明当模式中第j个字符与主串中相应字符“失配”时,在模式中需要重新和主串中该字符进行比较的字符位置。
max{k|1
1 其他情况
数组
矩阵
广义表
编码:将数据文件转换成0,1组成的二进制串,称之为编码。
//二叉树顺序存储
#define MAXTSIZE 100
Typedef TElemType SqBiTree[MAXTSIZE]
SqBiTree bt;
//二叉链表存储结构
typedef struct BiNode{
TElem Type data;
struct BiNode *lchild,*rchild;//左右孩子指针
}BiNode,*BiTree;
在n个结点的二叉链表中,有n+1个空指针域。
二叉树先序遍历算法
status PreOrderTraverse(BiTree T){
if(T==NULL) return OK;
else{
vist(T);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
中序遍历非递归算法
status InOredTraverse(BiTree T){
BiTree p;InitStack(S);p=T;
while(p||StackEmpty(S)){
if(p) {Push(S,p);p=p->lchild;}
else {Pop(S,q); printf("%c",T->data; p=q->rchild;)}
}
return Ok;
}
二叉树的层次遍历算法
void LevelOrder(BTNode *b){
BTNode *p;SqQueue *qu;
InitQueue(qu);//初始化队列
enQueue(qu,b);//根结点指针进入队列
while(!QueueEmpty(qu)){//队不为空,则循环
deQueue(qu,p);//出队结点p
printf("%c",p->data);//访问结点p
if(p->lchild!=NULL)enQueue(qu,p->lchild);//有左孩子将其进队
if(p->rchild!=NULL)enQueue(qu,p->rchild);//有右孩子将其进队
}
}
按先序遍历序列建立二叉树的二叉链表
ABC##DE#G##F###
status CreateBiTree(BiTree &T){
scanf(&ch);
if(ch=="#")T=NULL;
else{
if(!(T=(BiTNode*malloc(sizeof(BiTNode))))
exit(OVERFLOW);
T->data=ch;
CreateBiTree(T->lchild);
CreateBiTree(T->rchild);
}
return OK;
}
复制二叉树
int Copy(BiTree T,BiTree &NewT){
if(T==NULL){
NewT=NULL; return 0;
}
else{
NewT=new BiTNode;
NewT->data=T->data;
Copy(T->lchild,NewT->lchild);
Copy(T->rchild,NewT->rchild);
}
}
计算二叉树深度
int Depth(BiTree T){
if(T==NULL) return 0;
else {
m=Depth(T->lchild);
n=Depth(T->rchild);
if(m>n)return (m+1);
else return (n+1);
}
}
计算二叉树结点总数
int NodeCount(BiTree T){
if(T==NULL)
return 0;
else
return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
}
线索二叉树
typedef struct BiThrNode{
int data;
int Itag,rtag;
struct BiThrNode *lchild,*rchild;
}BiThrNode,*BiThrNode;
树的存储结构:
双亲表示法
typedef struct PTNode{
TElemType data;
int parent;//双亲位置域
}PTNode;
#define MAX TREE SIZE 100
typedef struct{
PTNode nodes[MAX_TREE_SIZE];
int r,n;
}PTree;
孩子链表
typedef struct CTNode {
int child;
struct CTNode *next;
}*ChildPtr;
typedef struct{
TElemType data;
ChildPtr firstchild;
}CTBox;
typedef struct{
CTBox node[MAX_TREE_SIZE];
int r,n;
}CTree;
孩子兄弟表示法(二叉链表表示法)
typedef struct CSNode{
ElemType data;
struct CSNode *firstchild,*nextsibling;
}CSNode,*CSTree;
树和森林
哈夫曼树:最优树,带权路径长度最短的二叉树
typedef struct{
int weight;
int parent,lch,rch;
}HTNode,*HuffmanTree;