数据结构与算法
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
第一章 绪论
第二章 线性表
第三章 树与二叉树
第四章 图
第五章 查找
第六章 排序
第二章 线性表
定义、抽象数据类型
- 线性表:零个或多个数据元素的有限序列
- ADT
线性表的实现
顺序存储
#define max 100
typedef ElemType int
struct LIST{
ElemType elments[max];
int last;
}
LIST L
单链表
struct celltype{
ElemType data;
celltype *next;
}
typedef celltype *LIST;
typedef celltype *position;
插入:
void Insert(ElemType x,position p,LIST &L)
{
position q;
q = new celltype;
q ->data = x;
q ->next = p->next;
p->next = q;
}
如何对某一结点进行前插操作?1.找到
a
i
−
1
a_{i-1}
ai−1的位置,然后采用后插操作2.值交换
删除操作:
void Delete(position p,LIST &L)
{
position q;
if(p->next != NULL)
{
q = p->next;
p->next = p->next->next;
free(q)
}
}
定位:
position Locate(ElemType x,LIST L)
{
position p;
p = L;
while(p->next != NULL)
{
if (p->next->data == x)
return p;
else
p = p->next;
}
return p;
}
提取:
ElemType Retrieve(position p,LIST L)
{
return p->next-data;
}
寻找前驱:
position Previous(position p,LIST L)
{
position q;
if(p == L->next)
cout<<"不存在前驱位置";
else
{
q = L;
while(q->next !=p)
q = q->next;
return q;
}
}
寻找后继:
position Next(position p,LIST L)
{
position q;
if(p->next == NULL)
cout<<"不存在后继位置";
else
{
q = p->next;
return q;
}
}
创建空链表:
position MaleNull(LIST &L)
{
L = new celltype;
L->next = NULL;
return L;
}
找尾结点:
position End(LIST L)
{
position q;
q = L;
while(q->next != NULL)
q = q->next;
return q;
}
单链表的整表创建:头插法、尾插法
静态链表
把线性表的元素存放在数组的单元中(不一定按逻辑顺序连续存放),每个单元不仅存放元素本身,而且还要存放其后继元素所在的数组单元的下标(游标)
以 next== 1 作为其结束的标志
静态链表的插入和删除操作与动态链表的相同
有一个空闲表用来在插入新空间时申请空间
typedef struct{
ElemType data;
int next;
}spacestr;
spacestr SPACE[maxsize];//存储池
typedef int position,Cursor;
初始化:
void Initialize()
{
int j;
for (j = 0;j< maxsize-1,j++)
{
SPACE[j].next = j+1;
}
SPACE[j].next = -1;
avail = 0;
}
可用空间的分配操作:
Cursor GetNode()
{
Cursor p;
if (SPACE[avail].next = -1)
p = -1
else
{
p = SPACE[avail].next;
SPACE[avail].next = SPACE[p].next;
}
return p;
}
可用空间的回收操作
void FreeNode(Cursor q)
{
SPACE[q.next]=SPACE[avail].next;
SPACE[avail].next = q;
}
插入:
void Insert(ElemType x,position p,spacestr *SPACE)
{
position q;
q = GetNode();
SPACE[q].data = x;
SPACE[q].next = SPACE[p].next;
SPACE[p].next = q;
}
删除:
void Delete(position p,spacestr *SPACE)
{
position q;
if(SPACE[p].next != -1)
{
q = SPACE[p].next;
SPACE[p].next = SPACE[q].next;
FreeNode(q);
}
}
双向链表
是在单链表的每个结点中,再 设置一个指向其前驱结点的指针域。
结点有两个指针域,一个指向直接后继,另一个指向直接前驱
struct dcelltype{
ElemType data;
dcelltype *next,*prior;
}
typedef dcelltype *DLIST;
typedef dcelltype *position;
插入:
void Insert(ElemType x, position p,DLIST &L)
{
s = new dcelltype;
s->data = x;
s->prior = p;
s->next = p->next;
p->next->prior =s;
p->next = s;
}
删除:
void Delete(position p,DLIST &L)
{
if(p->prior !=NULL)
p->prior->next = p->next;
if(p->next != NULL)
p->next->prior = p->prior;
delete p;
}
循环链表
将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为单循环链表,简称循环链表 (circular linked)
在表左端插入结点:
void LInsert(ElemType x,LIST &R)
{
celltype *p;
p = new celltype;
p->data = x;
if(R==NULL)
{
p->next = p;
R = p;
}
else
{
p->next = R->next;
R->next = p;
}
}
在表右端插入结点:
void RInsert(ElemType x,LIST R)
{
LInsert(x,R);
R = R->next;
}
栈
定义与操作
1、限定仅在表尾进行插入和删除操作的线性表
2、空栈:不含有任何数据元素的栈
3、栈顶和栈底:允许插入和删除的一端称为栈顶,另一端称为栈底
4、栈的操作:MakeNull(S),Top(S),Pop(S),Push(x,S),Empty(S)
顺序存储
struct STACK{
int top;
ElemType elements[maxlength];
} ;
置空:
void MakeNull(STACK &S)
{
S.top = maxlength;
}
测试栈S是否为空:
boolean Empty(STACK S)
{
if(S.top>maxlenth-1)
return TRUE;
else
return FALSE;
}
返回栈S的栈顶元素:
ElemType Top(STACK S)
{
if (Empty(S))
return NULLES;
else
return S.elements[S.top];
}
弹出栈:
void Pop(STACK &S)
{
if(Empty(S))
cout<<"Stack is empty!"<< endl;
else
S.top = S.top+1;
}
压入栈:
void Push(ElemType x,STACK &S)
{
if(S.top == 0)
cout<<"stack is full!"<< endl;
else
{
S.top = S.top-1;
S.elements[S.top] = x;
}
}
链式存储
struct node{
ElemType val;
node *next;
}
typedef node *STACK;
置空:
void MakeNull()
{
STACK S;
S = new node;
S->next = NULL;
}
入栈:
void Push(ElemType x,STACK S)
{
STACK stk;
stk = new node;
stk->val = elm;
stk->next=S->next;
S->next = stk;
}
出栈:
void Pop(STACK S)
{
STACK stk;
if(S->next)
{
stk=S->next;
S->next = stk->next;
delete stk;
}
}
返回栈S的栈顶元素:
ElemType Top(STACK S)
{
if(S->next)
return S->next->val;
else
reutrn NULLES;
}
测试栈S是否为空:
boolean Empty(STACK S)
{
if(S->next)
return FALSE;
else
return TRUE;
}
栈的递归调用
递归过程在实现时,需要自己直接或间接调用自己,层层向下递归,返回次序正好相反
队列
定义
只允许在一端进行插入操作,而另一端进行删除操作的线性表。
操作:MakeNull(Q) Front(Q) EnQueue(x,Q) DeQueue(Q) Empty(Q)
顺序存储
struct queue{
ElemType data[MaxSize];
int front;
int rear;
}
初始化:
void MakeNull(queue &Q){
Q.front = MaxSize-1;
Q.rear = MaxSize-1;
}
队列判空:
bool Empty(queue Q)
{
if (Q.rear == Q.front)
return TRUE;
else
return FALSE;
}
返回队首元素:
ElemType Front(queue Q)
{
if (Empty(Q))
return NULLESE;
else
{
Q.front = (Q.front+1)%MaxSize;
return Q.data[Q.front];
}
}
入队:
void EnQueue(ElemType x,QUEUE &Q)
{
if ((Q.rear+1)%MaxSize == Q.front)
cout<< "队列满";
else
{
Q.rear = (Q.rear+1)%MaxSize;
Q.data[Q.rear] = x;
}
}
出队:
void DeQueue(queue Q)
{
if (Empty(Q))
cout<< "空队列" << endl;
else
Q.front= (Q.front+1)%MaxSize;
}
链式存储
//结点
struct celltype{
ElemType data;
celltype *next;
};
//队列
struct queue{
celltype *front;
celltype *rear;
};
初始化与判空:
void MakeNull(queue &Q)
{
Q.front = new celltype;
Q.front->next = NULL;
Q.rear = Q.front;
}
Boolean Empty(queue &Q)
{
if (Q.rear == Q.front)
return TURE;
else
return FLASE;
}
入队:
void EnQueue(ElemType x,queue &Q)
{
q = new celltype;
q->data = x;
q->next = NULL;
Q.rear->next = q;
Q.rear =q;
}
出队:
void DeQueue(queue &Q)
{
if (Q.rear == Q.front)
cout<< "队空";
p = Q.front->next;
Q.front->next= p->next;
if(p->next == NULL)
Q.rear = Q.front;
delete p;
}
返回队首元素:
ElemType Front(queue Q)
{
if(Q.front->next)
return Q.front->next->data;
}
串
顺序串与链串
模式匹配
朴素模式匹配算法(Brute-Force,BF)
从主串S的第一个字符开始和模式 T 的第一个字符进行比较,若相等,则继续比较两者的后续字符;否则,从主串S 的第二个字符开始和模式 T 的第一个字符进行比较。
重复上述过程,直到T 中的字符全部比较完毕,说明本趟匹配成功;或 S 中字符全部比较完,则说明匹配失败。
int StrMatch_BF(char *S, char *T, int pos = 0)
{
/*S为主串 T 为模式,长度分别为了 lenS 和 lenT ;串采用顺序存储结构*/
i = pos;
j = 0;
while(i<=lenS && j<= lenT){
if(S[i] == T[j])
{
i++;
j++;
}
else{
i = i-j+1;
j = 0 ;
}
}
if(j>lenT)
return i-lenT+1;
else
return -1;
}
KMP算法:
void Getnext(int next[],String t)
{
int j=0,k=-1;
next[0]=-1;
while(j<t.length-1)
{
if(k == -1 || t[j] == t[k])
{
j++;k++;
next[j] = k;
}
else
k = next[k];//此语句是这段代码最反人类的地方,如果你一下子就能看懂,那么请允许我称呼你一声大神!
}
}
int KMP(String s,String t)
{
int next[MaxSize],i=0;j=0;
Getnext(t,next);
while(i<s.length&&j<t.length)
{
if(j==-1 || s[i]==t[j])
{
i++;
j++;
}
else j=next[j]; //j回退。。。
}
if(j>=t.length)
return (i-t.length); //匹配成功,返回子串的位置
else
return (-1); //没找到
}