线性表
1.顺序表
线性表的顺序存储结构即为顺序表。
(1)静态分配:
#include <stdio.h>
#define MaxSize 100 //定义线性表最大长度
typedef struct{
ElemType data[MaxSize]; //顺序表的元素
int length; //顺序表当前的长度
}SqList; //静态顺序表的定义
void InitList(SqList &L){
for(int i = 0; i < MaxSize; i++){
L.data[i] = 0;//初始化每一个data
}
L.length = 0; //set 长度为0
} //线性表相应的初始化
bool ListInsert(SqList &L,int i,ElemType e){
if(i<1 || i>L.length+1) //判断i是否在1~length+1返回内
return false;
if(L.length >= MaxSize) //判断list是否以及满了
return false;
for(int j=L.length; j >= i;j--)
L.data[j] = L.data[j-1];
L.data[i-1] = e;
L.length++;
return true; //插入成功
} //线性表插入操作
bool ListDelete(SqList &L,int i,ElemType &e){
if(i<1 || i>L.length) //判断删除的位置是否在合法范围内
return false;
e = L.data[i-1]; //保存删除的元素
for(int j = i;j<L.length;j++)
L.data[i-1] = L.data[i];
L.length--;
return true; //删除成功
} //线性表删除指定位置操作
ElemType GetElem(SqList&L,int i){
if(i<1 || i>L.length){
std::cout<<""<<std::endl;
return 0;
} //判断位置是否合法
return L.data[i-1];
}
int LocateElem(SqList&L,ElemType e){
for(int i = 0;i<L.length;i++) //寻找元素的位置
if(L.data[i] == e)
return i+1; //寻找成功返回位序
return 0;
} //线性表按元素值查找
int main(){
SqList L;
InitList(L);
}
(2)动态分配:
#include <stdio.h>
#include <cstdlib>
#define InitSize 100 //初始化表的长度
typedef struct{
ElemType *data; //数据类型的指针
int MaxSize,length; //容纳最大数量和当前数量
}SeqList;
void InitList(SeqList &L){
L.data = (ElemType *)malloc(sizeof(ElemType)*InitSize); //分配100单位的ElemType
//L.data = new ElemType(InitSize);
L.MaxSize = InitSize; //当前顺序表的最大容量
L.length = 0; //当前顺序表的长度
} //顺序表的初始化
void IncreaseSize(SeqList &L,int len){
ElemType *p = L.data;
L.data = (ElemType *)malloc(sizeof(ElemType)*(L.MaxSize + len)); //分配新空间
for(int i = 0;i<L.length;i++){
L.data[i] = p[i]; //将数据复制到新区域
}
L.MaxSize += len; //顺序表最大长度
free(p);
}
bool ListInsert(SeqList &L,int i,ElemType e){
if(i<1 || i>L.length+1) //判断i是否在1~length+1返回内
return false;
if(L.length >= L.MaxSize) //判断list是否以及满了
return false;
for(int j = L.length;j>=i;j--)
L.data[j] = L.data[j-1];
L.data[i-1] = e;
return true; //插入成功
} //线性表插入操作
bool ListDelete(SeqList &L,int i,ElemType &e){
if(i<1 || i>L.length) //判断是否位置合法
return false;
e = L.data[i-1]; //保存被删除的元素
for(int j=i;i<L.length;i++)
L.data[i-1] = L.data[i];
L.length--;
return true; //删除成功
} //线性表指定位置进行删除
ElemType GetElem(SeqList &L,int i){
if(i<1 || i>L.length){
std::cout<<""<<std::endl;
return 0;
} //判断位置是否合法
return L.data[i-1];
}
int LocateElem(SeqList &L,ElemType e){
for(int i = 0;i<L.length;i++) //寻找元素的位置
if(L.data[i] == e)
return i+1; //寻找成功返回位序
return 0;
} //线性表按元素值查找
int main(){
SeqList L;
InitList(L);
IncreaseSize(L,5);
return 0;
}
练习参考
01.删除最小值,并且返回其值,表中最后一个元素替代被删除元素的位置
算法思想:遍历寻找最小值并记住位置,结束之后删除替代操作即可。
bool DelMin(SqList &L,ElemType value){
if(L.length == 0)
return false;
int pos = 0;
for(int i = 1; i < L.length; i++)
if(L.data[i] < L.data[pos])
pos = i;
value = L.data[pos];
L.data[pos] = L.data[L.length - 1];
L.length--;
return true;
}
02.设计一个高效算法,将顺序表L的所有位置逆置,要求算法的空间复杂度为O(1)。
算法思想:遍历顺序表L前一半,第i个与第length-i+1个进行替换,一直到length/2(包含此元素)为止。
bool Reverse(SeqList &L){
if(L.length<1)
return false;
ElemType temp;
for(int i = 1; i <= L.length/2;i++){
temp = L.data[i-1];
L.data[i-1] = L.data[L.length-i];
L.data[L.length-i] = temp;
}
return true;
}
03.删除所有的值为x的元素,要求时间复杂度为O(n),空间复杂度为O(1)
算法思想:遍历顺序表所有元素,使用cnt = 0进行记录一共出现的x值元素的个数,判断L.data[i+cnt] == x,如果是则进行删除,cnt++进行下一轮判断,如果不是则有L.data[i] = L.data[i+cnt],i++即可完成;结束循环后L.length = i或者为L.length -= cnt;
bool Del_X_Value(SeqList &L,ElemType x){
if(L.length<1) //判断表是否为空
return false;
int i = 0; cnt = 0;
while(cnt+i<L.length){ //循环遍历表,查看每一个cnt+i元素是否为x
if(L.data[i+cnt] == x)
cnt++;
else{
L.data[i] = L.data[i+cnt];
i++;
}
}
L.length = i;
return true;
}
算法思想二:参考答案可知,使用cnt记录不等于x的元素个数,遍历整个数组,如果不等于x,将L.data[cnt] = L.data[i],更新cnt即可;
04.删除有序顺序表中给定值s与t之间的所有元素,如果s或t不合理或顺序表为空,则显示错误并退出
分析:有序顺序表,则说明表为单调递增
算法思想:首先找元素值大于s的最小序列元素,再找元素值小于t的最大序列元素,删除这段元素,其他元素进行前移即可。
bool Del_s_t(SqList &L,ElemType s,ElemType t){
int i,j;
if(L.length<1 && s>=t)
return false;
for(i=0; L.data[i] < s && i < L.length; i++);
if(i>=L.length)
return false;
for(j = i; L.data[j] <= t; j++);
for(; j < L.length; j++,i++)
L.data[i] = L.data[j];
L.length = i;
return true;
}
05.删除顺序表中给定值s与t之间的所有元素,如果s或t不合理或顺序表为空,则显示错误并退出
bool Delete_s_t(SeqList &L,int s,int t){
if(L==nullptr || s>=t){
std::cout<<"删除操作失败"<<std::endl;
return false;
}
int cnt = 0;
for(int i = 0;i<L.length;i++)
if(L.data[i]<s || L.data[i]>t){
L.data[cnt] = L.data[i];
cnt++;
}
L.length = cnt;
return true;
}
06.从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同
算法思想:首先定义cnt记录不合法元素的个数,从第一个元素开始到最后一个元素,扫描当前元素,如果合法则把该元素发在前移cnt个位置,如果不合法cnt++;
bool Del_Repeat(SeqList &L){
int cnt = 0;
for(int i = 1; i < L.length; i++)
if(L.data[i] == L.data[i-1])
cnt++;
else
L.data[i-k] = L.data[i];
L.length -= cnt;
return true;
}
07.有两个有序顺序表,合并为一个新的有序表,并由函数返回结果顺序表
bool ListMerge(SeqList &L1,SeqList &L2,SeqList &L){
if(L.length < L1.length+L2.length)
return false;
L.length = L1.length + L2.length;
int i1 = 0, i2 = 0;
for(int i = 0; i<L.length,i++)
if((L1.data[i1] <= L2.data[i2] && i1<L1.length)||i1>=L1.length){
L.data[i] = L1.data[i1];
i1++;
}else(i2 < L2.length){
L.data[i] = L2.data[i2];
i2++;
}
return true;
}
2.链表
链式存储结构
单链表
1.结点的定义
#include <iostream>
typedef struct LNode{ //定义单链表节点
ElemType data; //数据域
struct LNode *next; //指针域
}LNode, *LinkList;
2.初始化
(1)不带头节点的初始化
bool InitList(LinkList &L){
L = nullptr; //空表,无节点
return true;
} //不带头节点的初始化
(2)带头节点的初始化(一般使用这个)
bool InitList(LinkList &L){
L = (LNode *)malloc(sizeof(LNode));
if(L==nullptr)
false;
L->next = nullptr;
return true;
} //带头节点的初始化
3.插入操作
(1)按位序插入
不带头节点的插入操作:
bool InsertList(LinkList &L,int i,ElemType e){
if(i<1) //判断是否i位置异常
return false;
if(i == 1){
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next = p;
L = s;
return true;
}
LNode *p = L;
int j = 1;
while(p != nullptr && j<i-1){ //找到第i-1个位置的节点
p = p->nullptr;
j++;
}
if(p==nullptr) //判断是否为空,如为空则i>链表的长度
return false;
LNode *s = (LNode *)malloc(sizeof(LNode)); //进行插入操作
s->data = e;
s->next = p->next;
p->next = s->next;
return true;
} //不带头节点的插入操作
带头结点的插入操作
bool InsertList(LinkList &L,int i,ElemType e){
if(i<1)
return false;
LNode *p = L;
int j = 0;
while(p!=nullptr && j<i-1){
p = p->next;
j++;
}
if(p==nullptr)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = e;
s->next = p->next;
p->next = s;
return true;
} //带头节点的插入操作
(2)指定结点的后插操作
bool InsertNextNode(LNode *p,ElemType e){
if(p == nullptr)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if(s == nullptr)
return false;
s->data = e;
s->next = p-next;
p->next = s;
return true;
}
(3)指定结点的前插操作
1.指定节点前面插入一个节点
bool InsertPriorList(LNode *p,LNode *s){
if(p == nullptr ||s == nullptr)
return false;
s->next = p-next;
p-next = s;
ElemType temp = p->data;
p->data = s-data;
s->data = temp;
return true;
}
2.指定结点前面插入元素e
bool InsertPriorList(LNode *p,ElemType e){
if(p==nullptr)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if(s==nullptr)
return false;
s->next = p->next;
p-next = s;
s->data = p->data;
p->data = e;
return true;
}
4.删除操作
(1)按位序进行删除
带头结点的删除操作:
bool ListDelete(LinkList &L,int i,ElemType &e){
if(i<1)
return false;
int j = 0;
LNode *p = L;
while(p!=nullptr && j < i-1){
p = p->next;
j++;
}
if(p==nullptr || p->next==nullptr)
return false;
LNode *q = p->next;
e = q->data;
p->next = q->next;
free(q);
return true;
}//带头结点的删除操作
不带头结点的删除操作:
bool ListDelete(LinkList &L,int i,ElemType &e){
if(i<1)
return falses;
LNode *p = L;
if(i == 1){
e = L.data;
L = L.next;
free(p);
}
int j = 1;
while(p!=nullptr && j<i-1){
p = p->next;
j++;
}
if(p==nullptr || p->next==nullptr)
return false;
LNode *q = p->next;
e = q->data;
p->next = q->next;
free(q);
return true;
}
(2)删除指定结点p
算法思想:把后一个结点的data复制给p->data,p结点-next = 后一个结点next,释放后一个结点。(算法缺陷,当p为最后一个结点时,只能遍历所有结点进行删除)
code:
bool ListDelete(Lnode *p,ElemType &e){
if(p==nullptr)
return false;
if(p->next==nullptr)
return false;
e = p->data;
LNode *s = p-next;
p->data = s->data;
p->next = s->next;
free(s);
return true;
}
5.查找
(1)按序号查找结点(含头结点)
算法思想:判断i是否合法,不合法返回nullptr,遍历链表到相应位置。
LNode *GetElem(LinkList &L,int i){
if(i<1)
return nullptr;
LNode *p = L;
int j = 0;
while(p != nullptr && j<i){
p = p->next;
j++;
}
return p;
}
(2)按值查找结点(含头结点)
算法思想:遍历查找
LNode *LocateElem(LinkList &L,ElemType e){
LNode *p = L->next; //需注意这个地方必须是L->next,因为L->data可能也是e,级小概率。
while(p != nullptr && p->data != e)
p = p->next;
return p;
}
6.单链表长度(含头结点)
int Length(LinkList &L){
LNode *p = L;
int j = 0;
while(p->next != nullptr){
p = p->next;
j++;
}
return j;
}
7.单链表的建立
如果有很多ElemType,要把它们存到一个单链表里边。
1.初始化单链表
2.每次取一个数据元素,插入到表头或者表尾。
(1)尾插法(带头结点)
LinkList List_TailInsert(LinkList &L){
L = (LinkList)malloc(sizeof(LNode));
LNode s,*p = L;
int x;
scanf("%d",&x);
while(x != 9999){
s = (LNode *)malloc(sizeof(LNode));
s.data = x;
p->next = s;
p = s;
scanf("%d",&x);
}
p->next = nullptr;
return L;
}
(2)头插法(带头结点)
LinkList List_HeadInsert(LinkList &L){
L = (LinkList)malloc(sizeof(LNode));
LNode s;
L->next = nullptr;
int x;
scanf("%d",&x);
while(x != 9999){
s = (LNode *)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;
scanf("%d",&x);
}
return L;
}
思考:链表的逆置
算法思想:建立一个新链表,删除并单独取出原链表的第一个结点,使用头插入新链表。
LinkList ListReverse(LinkList &L){
if(L==nullptr)
return nullptr;
LinkList s = (LinkList)malloc(sizeof(LNode));
s->next = nullptr;
LNode *p = nullptr;
while(L->next != nullptr){
p = L->next;
L->next = p->next;
p->next = s->next;
s-next = p;
}
L->next = s->next;
free(s);
return L;
}
双链表
单链表前向找值是极其不方便,需要重新进行遍历,如果能直接前向找值,就极其减小时间复杂度。
在单链表的结构基础之上,加了一个前向指针Prior实现。
1.结点的定义
typedef struct DNode{
ElemType data;
struct DNode *prior,*next;
}DNode, *DLinkList;
2.初始化链表
DLinkList InitDLinkList(DLinkList &L){
L = (DLinkList)malloc(sizeof(DNode));
if(L == nullptr)
return nullptr;
L->next = nullptr;
L->prior = nullptr;
return L;
}
3.双链表的插入操作
在p结点后插入s结点
bool InsertNextDNode(DNode *p,DNode *s){
if(p == nullptr || s == nullptr)
return false;
s->next = p->next;
if(p-next != nullptr)
p->next->prior = s;
p->next = s;
s-prior = p;
return true;
}
4.双链表的删除操作
在p结点后删除s结点
bool DeleteNextDNode(DNode *p){
if(p==nullptr || p->next ==nullptr)
return false;
DNode *s = p->next;
p->next = s-next;
if(p->next != nullptr)
p->next->prior = p;
free(s);
return true;
}
5.遍历
后向遍历:
while(p!=nullptr){
p = p->next;
}
前向遍历:
while(p!=nullptr){
p = p->prior;
}
向前遍历(跳过头结点)
while(p->prior != nullptr){
p = p->prior;
}
循环链表
1.循环单链表
在单链表的基础上进行改变,最后一个元素的next指向不再为nullptr,为L,链表结点。
初始化操作
bool InitList(LinkList &L){
L = (LNode *)malloc(sizeof(LNode));
if(L==nullptr)
false;
L->next = L;
return true;
} //带头节点的初始化
判断单链表是否为空
bool Empty(LinkList &L){
if(L->next == L)
return ture;
else
return false;
}
判断是否为表尾结点
bool isTail(LinkList &L,LNode *p){
if(p->next == L)
return true;
else
return false;
}
思考:其实可以改良循环单链表,头部结点可以加一个prior方便快速访问尾节点。
2.循环双链表
以双链表的结构为基础进行改造,最后一个元素的next成员指向头结点。
初始化
DLinkList InitDLinkList(DLinkList &L){
L = (DLinkList)malloc(sizeof(DNode));
if(L == nullptr)
return nullptr;
L->next = L;
L->prior = L;
return L;
}
判断是否为空表
bool Empty(DLinkList &L){
if(L->next == L)
return ture;
else
return false;
}
判断是否为表尾结点
bool isTail(LinkList &L,LNode *p){
if(p->next == L)
return true;
else
return false;
}
关于循环双链表的删除操作
在最后需要判断删除的元素是否是最后一个结点的后结点,即头结点。
练习
01设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点。
算法思想:f(L,x)对当前指针指向的结点,进行判断是x则L = L->next,并且调用f(L,x)。
终止条件:f(L,x)不做任何事,即L为nullptr。
bool Del_x(LNode *&L,ElemType x){
if(L==nullptr)
return true;
if(L->data == x){
LNode *p = L;
L = L->next;
free(p);
return Del_x(L,x);
}
return Del_x(L->next,x);
}
栈,队列和数组
栈
是一种操作受限的线性表,只允许在一端进行插入删除操作。
基本操作:
InitStack(&S);
StackEmpty(S);
Push(&S,x);
Pop(&S,&x);
GetTop(S,&x);
DestroyStack(&S);
1.顺序栈
定义
#define MaxSize 50;
typedef struct{
ElemType data[MaxSize];
int top;
}SqStack;
初始化
void InitStack(SqStack &S){
S.top = -1;
}
增加
bool Push(SqStack &S,ElemType x){
if(top+1 >= MaxSize)
return false;
MaxSize[++S.top] = x;
return true;
}
判断是否为空
bool StackEmpty(SqStack &S,ElemType x){
if(S.top == -1)
return true;
else
return false;
}
出栈操作
bool Pop(SqStack &S,ElemType &x){
if(S.top == -1)
return false;
x = S.data[S.top--];
return true;
}
得到栈顶元素
bool GetTop(SqStack &S,ElemType &x){
if(S.top == -1)
return false;
x = S.data[S.top];
return true;
}
2.共享栈
定义:
#define MaxSize 10
typedef struct{
ElemType data[MaxSize];
int top0 = -1;
int top1 = MaxSize;
}ShStack;
void InitStack(ShStack &S){
S.top0 = -1;
S.top1 = MaxSize;
}
3.链栈
带头结点的定义
typedef struct LinkNode{
ElemType data;
typedef struct LinkNode *next;
}*LinkStack;
void InitStack(LinkStack &S){
S = (LinkStack)malloc(sizeof(LinkNode));
S->next = nullptr;
}
不带头结点链表
定义
//定义
typedef struct LinkNode{
ElemType data;
typedef struct LinkNode *next;
}*LinkStack;
//初始化
void InitStack(LinkStack &S){
S = nullptr;
}
判断是否为空
bool StackEmpty(SqStack &S){
if(S==nullptr)
return true;
else
return false;
}
Push进栈
bool Push(SqStack &S,ElemType e){
LinkNode *p = (LinkNode *)malloc(sizeof(LinkNode));
if(p==nullptr)
return false;
p->next = S;
S = p;
return true;
}
Pop出栈
bool Pop(SqStack &S,ElemType &e){
if(S==nullptr)
return false;
e = S.data;
S = S->next;
return true;
}
读栈顶元素
bool GetTop(SqStack &S,ElemType &e){
if(S==nullptr)
return false;
e = S->data;
return true;
}
队列
定义:操作受限的线性表,只能在一端进行删除另一端进行添加的线性表。
队头:元素删除的一端。
队尾:插入的一端。
队列的基本操作
InitQueue(&Q);
QueueEmpty(Q);
EnQueue(&Q,x);
DeQueue(&Q,&x);
GetHead(Q,&x);
1.基于顺序结构的队列
(本质上是循环队列,rear是最后一个元素的下一个序列)
定义
#define MaxSize 50;
typedef struct{
ElemType data[MaxSize];
int front,rear;
}SqQueue;
//初始化
bool InitQueue(SqQueue &Q){
if(Q == NULL)
return false;
Q.front = Q.rear = 0;
return true;
}
判断队列是否为空
bool QueueEmpty(SqQueue &Q){
if(Q.rear == Q.front)
return true;
else
return false;
}
判断队列是否已满
bool QueueFull(SqQueue Q){
if(((Q.rear+1)%MaxSize) == Q.front)
return true;
else
return false;
}
入队操作
bool EnQueue(SqQueue &Q,ElemType x){
if(QueueFull(Q))
return false;
Q.data[Q.rear] = x;
Q.rear = (Q.rear+1)%MaxSize;
}
出队操作
bool DeQueue(SqQueue &Q,ElemType &x){
if(QueueFull(Q))
return false;
x = Q.data[Q.front];
Q.front = (Q.front + 1)%MaxSize;
return true;
}
2.队列的链式存储
用链式存储实现队列的操作。
定义
typedef struct LinkNode{
ElemType data;
struct LinkNode *next;
}LinkNode;
typedef struct{
LinkNode *front, *rear;
}LinkQueue;
初始化
不带头结点的初始化:
void InitQueue(LinkQueue &L){
L.rear = nullptr;
L.front = nullptr;
}
带头结点的初始化:
void InitQueue(LinkQueue &L){
L.front = L.rear = (LinkNode*)malloc(sizeof(LinkNode));
if(L.rear == nullptr)
return false;
L.rear->next = nullptr;
}
入队操作
不带头结点:
bool EnQueue(LinkQueue &Q,ElemType e){
q = (LinkNode*)malloc(sizeof(LinkNode));
if(q==nullptr)
return false;
q->data = e;
q->next = nullptr;
if(Q.rear == nullptr){
Q.front = q;
Q.rear = q;
}else{
Q.rear->next = q;
Q.rear = q;
}
return true;
}
带头结点:
bool EnQueue(LinkQueue &Q,ElemType e){
q = (LinkNode*)malloc(sizeof(LinkNode));
if(q==nullptr)
return false;
q->data = e;
q->next = nullptr;
Q.rear->next = q;
Q.rear = q;
return true;
}
出队操作
不带头结点:
bool DeQueue(LinkQueue &Q,ElemType &e){
if(Q.rear == nullptr)
return false;
e = Q.front->data;
LinkNode *p = Q.front;
Q.front = Q.front->next;
if(Q.rear == Q.front){
Q.rear = nullptr;
Q.front = nullptr;
}
free(p);
return true;
}
带头结点:
bool DeQueue(LinkNode &Q,ElemType &e){
if(Q.rear == Q.front)
return;
LinkNode *p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if(Q.rear==p)
Q.rear = Q.front;
free(p);
return true;
}
获取队头元素
不带头结点:
bool GetHead(LinkQueue &Q,ElemType &e){
if(Q.front == nullptr)
return false;
e = Q.front->data;
return true;
}
带头结点的:
bool GetHead(LinkQueue &Q,ElemType &e){
if(Q.rear == Q.front)
return false;
e = Q.front->next->data;
return true;
}
3.栈和队列的应用
1.栈在括号匹配中的应用
算法分析:
#include <iostream>
#define MaxSize 100
typedef struct{
char data[MaxSize];
int top;
}SqStack;
bool bracketCheck(char str[], int length){
SqStack S;
InitStack(S);
char TopElem;
for(int i = 0; i < length; i++){
if(str[i]=='(' || str[i]=='{' || str[i]=='[')
if(!Push(S,str[i]))
return false;
else{
if(StackEmpty())
return false;
Pop(S,TopElem);
if(str[i] == ')' && TopElem != '(')
return false;
if(str[i] == ']' && TopElem != '[')
return false;
if(str[i] == '}' && TopElem != '{')
return false;
}
}
return StackEmpty(S);
}
void InitStack(SqStack &S){
//不带头结点的初始化
S.top = -1;
}
//压栈
bool Push(SqStack &S,char e){
if(S.top+1 >= MaxSize)
return false;
S.data[++S.top] = e;
return true;
}
//出栈
bool Pop(SqStack &S,char &e){
if(S.top == -1)
return false;
e = S.data[S.top];
return true;
}
//栈是否为空
bool StackEmpty(SqStack &S){
if(S.top == -1)
return false;
else
return true;
}
2.栈在表达式的计算
在此如果学会了栈在中缀表达式的应用。
首先建立两个栈,一个运算栈,一个操作栈。
给定一个表达式,从左边往右扫描,操作数压入操作栈,运算符压入运算栈,到遇到一个运算符时,即可开始比较运算符栈里面的优先级,判断下一步操作是压入还是计算。
串
串的定义和实现
串的定义
- 定长顺序存储表示
#include <iostream>
#define MAXLEN 255
typedef struct{
char ch[MAXLEN];
int length;
}SString;
- 堆分配存储表示
typedef struct{
char *ch;
int length;
}HString;
- 块链存储表示
typedef struct StringNode{
char ch[4];
struct StringNode* next;
}StringNode, *String;
串的操作
- StrAssign(&T,chars):赋值操作。把串T复制为chars
bool StrAssign(char *a,char *b,int index)//--1
{
//a,b不为空
if(a == nullptr || b == nullptr)
{
return false;
}
//取a串b串中最长的长度
int size = StrLength(a) > StrLength(b)-index ? StrLength(a):StrLength(b)-index;
for(int i = 0;i < size;i ++)
{
a[i] = b[index + i];
}
return true;
}
后面有时间再更新赶进度
参考文章
串的模式匹配
1.朴素模式匹配算法
int Index(SString S,SString T){
int i=1,j=1;
while(i<=(S.length-T.length+1) && 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;
}
2.KMP算法
int Index_KMP(SString S,SString T,int Next[]){
int i=1, j=1;
while(i<=(S.length-T.length+1) && j<=T.length){
if(j==0||S.ch[i]==T.ch[j]){
++i;++j;
}
else
j = next[j];
}
if(j>T.length)
return i-T.length;
else
return 0;
}
树
线索二叉树
存储结构:
#include <iostream>
using namespace std;
typedef struct ThreadNode{
ElemType data;
bool ltag,rtag;//int ltag,rtag;
ThreadNode * lchild,rchild;
}ThreadNode, *ThreadTree;
中序线索二叉树的构造
通过中序遍历对二叉树线索化的递归算法如下:
void InThread(ThreadTree &p,ThreadTree &pre){
if(p!=nullptr){
InThread(p->lchild,pre);
if(p->lchild==nullptr){
p->lchild = pre;
p->ltag = true;
}
if(pre != nullptr&&pre->rchild==nullptr){
pre->rchild = p;
pre->rtag = true;
}
pre = p;
InThread(p->rchild,pre);
}
}
中序遍历建立中序线索二叉树的主过程算法如下:
void CreateInThread(ThreadTree T){
if(T!=nullptr){
ThreadTree pre = nullptr;
InThread(T,pre);
pre-rchild = nullptr;
pre->rtag = true;
}
}
有时间再慢慢更新