数据结构代码实现之线性表

线性表

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.栈在表达式的计算

在此如果学会了栈在中缀表达式的应用。
首先建立两个栈,一个运算栈,一个操作栈。
给定一个表达式,从左边往右扫描,操作数压入操作栈,运算符压入运算栈,到遇到一个运算符时,即可开始比较运算符栈里面的优先级,判断下一步操作是压入还是计算。

串的定义和实现

串的定义

  1. 定长顺序存储表示
#include <iostream>
#define MAXLEN 255

typedef struct{
    char ch[MAXLEN];
    int length;
}SString;
  1. 堆分配存储表示
typedef struct{
    char *ch;
    int length;
}HString;
  1. 块链存储表示
typedef struct StringNode{
    char ch[4];
    struct StringNode* next;
}StringNode, *String;

串的操作

  1. 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;
    }
}

有时间再慢慢更新

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值