IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 23王道数据结构栈、队列、树、图、查找章节相关算法题总结(伪代码) -> 正文阅读

[数据结构与算法]23王道数据结构栈、队列、树、图、查找章节相关算法题总结(伪代码)

3.判断所给的操作序列是否合法,假设操作序列已经存入一维数组中

算法思想:遍历数组,统计进栈和出栈操作的次数,若不等则序列非法

非法的情况:

①空栈时执行出栈操作,即出栈操作次数大于进栈操作次数,在执行过程中查看

②最后栈不为空,即进栈操作次数大于出栈操作次数,执行操作结束后查看

bool Judge(char arr[]{

    int count1 = 0,count2 = 0;

    for(int i = 0;i !='\0';i++){

        if(arr[i] == 'I'){
            count1++;
        }else{
            count2++;
        }

        if(count2 > count1){
            printf("序列非法");
            return false;
        }
    }

    if(count1 != count2){
            printf("序列非法");
            return false;
    }

     printf("序列合法");
     return true;
}

4.判断表头指针为L的字符单链表是否对称

算法思想:定义一个字符数组,当作栈使用,先进后出,让链表的前一半的字符进栈,后出栈与链表后一半的字符一一做比较,若全相等,则是对称字符链表

bool Judge_Char_Link(LinkList L,int n){//假设L带头节点,n为链表长度
    
    //初始化栈
    char arr[n/2];
    int top = -1;

    LinkList cur = L->next;

    //将链表前半部分元素入栈(n为奇数时,不包括中间节点)
    for(int i = 0;i < n/2;i++){

        arr[++top] = cur->val;
        cur = cur->next;

    }

    if(n%2 != 0){//n为奇数时,让指针指向中间节点的下一个节点
        cur = cur->next;
    }

    //从栈顶至栈底与链表后半部分元素进行一一比较
    while(top > -1 && cur->val == arr[top]){
        top--;
        cur = cur->next;
    }    

    if(top != -1){
        return false;
    }else{
        return true;
    }
}

5.共享栈的进栈、出栈操作算法

算法思想:定义一个变量记录要操作的栈号,1表示栈指针初值为-1的栈,2表示栈指针初值为MaxSize的栈,入栈判满,出栈判空

typedef struct{
    ElemType val[MaxSize];
    int top[2];
}SqStack;//共享栈结构

//入栈操作
bool Push(SqStack S,int i,ElemType x){
    
    if(i < 1 || i > 2){
        print("栈号非法");
        return false'
    }

    if(S.top[0] + 1 == S.top[1]){//栈满
        return false;
    }

    switch(i){

        case 1:
            S.val[++S.top[0]] = x;
            return true;
            break;

        case 2:
            S.val[--S.top[1]] = x;
            return true;
            break;
    }

}

//出栈操作
bool Pop(SqStack S,int i,ElemType &x){

   if(i < 1 || i > 2){
        print("栈号非法");
        return false'
    }

    switch(i){

        case 1:
            if(S.top[0] == -1){//1号栈空
                return false;
            }else{
                x = S.val[S.top[0]--];
                return true;
            }

        case 2:

            if(S.top[1] == MaxSize){//2号栈空
                return false;
            }else{
                x = S.val[S.top[1]++];
                return true;
            }
 }

1.带标志域循环队列的入队和出队操作算法

算法思想:用标记域区分rear==front时栈空或栈满

typedef struct{
    ElemType queue[Maxsize];
    int front,rear;
    int tag;//初始时rear == front此时tag = 0,表示队空,插入导致rear==front此时tag=1,表示队满
}SqQueue;

bool EnQueue(SqQueue Q,ElemType x){

    if(rear == front && tag == 1){//队满
        return false;
    }    
    
    Q.rear = (Q.rear + 1)%Maxsize;
    Q.queue[Q.rear] = x;
   
    Q.tag = 1;//可能队满
    return true;
}

bool DeQueue(SqQueue Q,ElemType &x){
    
    if(Q.front == Q.rear && Q.tag == 0){
        print("队空");
        return false;
    }
    
    Q.front = (Q.front + 1)%Maxsize;
    x = Q.queue[Q.front];
    
    Q.tag = 0;//可能队空
    return true;
}

2.借助于空栈S,将队列Q中的元素进行逆置

算法思想:将队中元素出队入栈,在出栈入队

void Revese_Queue(SqStack &S,SqQueue Q){

    while(QueueEmpty(Q) != true){
        DeQueue(Q,x);
        Push(S,x);
    }

    while(StackEmpty(S) != true){
        Pop(S,x);
        EnQueue(Q,x);     
    }
}

3.用两个栈S1、S2模拟队列入队,出队以及判断队列是否为空

算法思想:两个栈规格相同

①入队操作:入队判满,如果S1满且S2栈不为空,则队满,否则若S1栈未满,入S1栈,若S1满,S2栈为空,将S1栈中元素出栈压入S2栈,再将其压入S1栈。

②出队操作:出队判空,若S1,S2栈均为空,则队空,否则若S2栈不为空,则出栈元素,若S2栈为空且S1栈不为空,将S1栈元素出栈压入S2栈中,再将其出栈。

//判断队空
bool QueueEmpty(SqStack S1,SqStack S2){
    if(StackEmpty(S1) && StackEmpty(S2)){
        return true;
    }else{
        return false;
    }
}

//入队操作
bool EnQueue(SqStack S1,SqStack S2,ElemType x){
    
    if(StackOverflow(S1)){//StackOverflow是判断栈满函数

        if(StackEmpty(S2) != true){
            return false;
        }else{
            while(StackEmpty(S1) != true){
                Pop(S1,cur);
                Push(S2,cur);
            }
            Push(S1,x);
            return true;
        }
        
    }else{
        Push(S1,x);
        return true;
    }  
}


//出队操作
bool DeQueue(Stack &S1,Stack &S2,EmleType &x){

    if(QueueEmpty(S1,S2)){
        return false;
    }else if(StackEmpty(S2) != true){
        Pop(S2,x);
        return true;
    }else{
        while(StackEmpty(S1) != true){
            Pop(S1,cur);
            Push(S2,cur);
        }
        Pop(S2,x);
        return true;
    }
}

4.求以孩子兄弟存储结构的森林(树)的叶子结点数

算法思想:原树中的叶子结点就是孩子兄弟存储结构中左孩子结点为空的结点,注意树没有严格的左右孩子节点之分,孩子节点从左到右

typedef struct CSNode{
   struct BiTNode *lchild,*rsibling;
   ElemType val;
}CSNode,*CSTree;

int leafNodeNumber_dfs(CSTree root){

    if(!root){
        return 0;
    }else if(root->lchild){//若当前节点有左孩子
        return leafNodeNumber_dfs(root->lchild) + leafNodeNumber_dfs(root->rsibling);
    }else{//无左孩子节点,叶子节点加1
        return 1+leafNodeNumber_dfs(root->rsibling);
    }   
}

5.树以孩子兄弟为存储结构,设计递归算法求树的深度

算法思想:原树高就是在孩子兄弟存储结构中左子树高度+1和右兄弟子树高度两者的最大者

int postOrder(CSTree root){

    if(!root){
        return 0;
    }
    
    int lchildHight = postOrder(root->lchild);
    int rsiblingHight = postOrder(root->rsibling);

    return lchildHight + 1 > rsiblingHight ? lchildHight + 1 : rsiblingHight;
}

6.已知一棵树的层次序列和每一个结点的度,构造此树的孩子-兄弟链表

算法思想:按照层次序列遍历各个顶点,若当前顶点的度大于1,表示该顶点有多个孩子,让当前顶点的左孩子指针指向第一个孩子节点,并从左至右依次链接孩子节点。

void CreateCsTree_Degree(CsTree &T,DateType e[],int degree[],int n){

    CsTree pointer = (CsTree)malloc(sizeof(CsNode)*MaxSize);
    
    int i,j,d,k = 0;
    for(i= 0;i < n;i++){//初始化
        pointer[i] = e[i];
        pointer[i]->lchild = pointer[i]->rsibling = NULL;
    }

    for(int i = 0;i < n;i++){//按照层次序列遍历各个节点

        d = degree[i];//获取当前节点的度即孩子个数

        if(d){//如果该节点有孩子节点

            k++;//孩子节点序号
            
            pointer[i]->lchild = pointer[k];//当前节点的左指针指向其左孩子节点
        
            for(int j = 1;j < d;j++){//若左孩子有兄弟节点,让孩子节点的右指针逐个指向右兄弟

                k++;
                pointer[k-1]->rsibling = poninter[k];

            }
        }
    }
}

4.将图的邻接表表示转化为邻接矩阵表示的算法

算法思想:从上到下扫描顶点表的边表结点,若顶点i有边表结点j,则邻接矩阵arcs[i][j] = 1;

void convert(ALGraph G,int arcs[MaxVertexNum][MaxVertexNum]){//邻接矩阵已初始化

    for(int i = 0;i < G.vexnum;i++){

        ArcNode* cur = G.vertices[i].first;

        while(cur){
            arcs[i][cur->adjvex] = 1;
            cur = cur->next;
        }
    }
}

6.当无向图G中度为奇数的顶点个数为不大于2的偶数时则该图存在EL路径,判断图是否存在EL路径,图用邻接矩阵存储

算法思想:遍历邻接矩阵中各顶点的度,统计度为奇数的顶点个数

bool isExistEL(MGraph G){
    
    int oddDegreeNum = 0;
    
    for(int i = 0;i < G.vexnum;i++){

        int degree = 0;
        
        for(int j = 0;i < G.vernum;j++){

            if(G.Edge[i][j] == 1){
                degree++;
            }
        }

        if(degree % 2 != 0){
            oddDegreeNum++;
        }      
    }

    if(oddDegreeNum == 0 || oddDegreeNum == 2){
        return true;
    }else{
        return false;
    }
}

2.判断无向图G是否为一颗树

算法思想:无向图G若为一棵树即为n个顶点,边数为n-1的连通图,遍历该图,若一次能够访问所有顶点则表示连通,且边数为顶点数减一表示该图为树

int vNum,aNum;//记录无向图的边数和顶点数

bool isTree(ALGraph G){

    for(int i = 0;i < G.vexNum;i++){//初始化顶点访问标记数组
        visited[i] = false;
    }

    DFS(G,1);//从顶点1开始遍历图

    if(G.vexNum == vNum && arcNum == 2*(vNum-1))){//判断是否连通且是否为树(边数为顶点数减一)
        return true;
    }else{
        return false;
    }

    
}

void DFS(ALGraph G,int v){
    
    //访问并标记该顶点
    visit(v);
    visited[v] = true; 
    
    vNum++;//统计顶点数

    struct ArcNode* cur = G.vertices[v].first;

    while(cur){

        aNum++;//统计边数

        if(!visited[cur->adjvex]){
            DFS(G,cur->adjvex);
        }
        
        cur = cur->next; 
    } 
}

3.图的深度优先遍历DFS算法的非递归算法(图采用邻接表存储结构)

算法思想:借助于栈,将当前出栈节点的各邻节点依次入栈并标记已入栈,待出栈时,再访问节点

void DFS_Non_RC(ALGraph G,int v){

    SqStack S;
    InitStack(S);//初始化栈

    for(int i = 0;i < G.vexnum;i++){//初始化进栈标记数组
        visited[i] = false;
    }

    Push(S,v);
    visited[v] = true;//标记顶点v是否进栈
        
    while(StackEmpty(S) != true){//从各顶点边表的右至左进行深度优先遍历

        Pop(S,v);
        visit(v);//访问顶点v
        struct ArcNode* cur = G.vertices[v].first;

        while(cur){
        
            if(!visited[cur->adjvex]){
                Push(S,cur->adjvex);    
                visited[cur->adjvex] = true;      
            }
            cur = cur->next;
        }     
    }
}

4.分别用基于DFS和BFS算法判断以邻接表为存储结构的有向图中是否存在由顶点vi到vj的路径(i!=j)

算法思想:从顶点vi出发可以遍历到顶点vj就表示顶点vi到vj有路径

bool isRoadDFS(ALGraph G,int i,int j){

    if(i == j){
        return true;
    }
  
    visited[i] = true;

    struct ArcNode* cur = G.vertices[i].first;
    
    while(cur){

        if(!visited[cur->adjvex]){
            isRoadDFS(G,cur->adjvex,j);
        }

        cur = cur->next;
    } 

    return false;
}

bool isRoadBFS(ALGraph G,int i,int j){

    SqQueue Q;
    InitQueue(Q);

    visit(i);
    EnQueue(Q,i);
    visited[i] = true;//访问进队并标记

    while(QueueEmpty(Q) != true){
        
        DeQueue(Q,i);
        if(i == j){//出队并检查该顶点是否为目标顶点
            return true;
        }
    
        struct ArcNode* cur = G.vertices[i].first;

        while(cur){//将当前顶点的邻接点访问进队并标记

            if(!visited[cur->adjvex]){
                visit(cur->adjvex);
                EnQueue(Q,cur->adjvex);
                visited[cur->adjvex] = true;
            }
            cur = cur->next;
        }   
    }

    return false;
}

5.输出顶点vi到vj的所有简单路径(图用邻接表存储)

算法思想:由于设置了访问标记数组,故vi到vj的路径必是简单路径

void FindPath(ALGraph G,int v1,int v2,int path[],int d){
    //v1和v2是顶点vi和vj的数组下标,path数组存储vi到vj的路径,d是path数组的下标,初值为0

    path[d++] = v1;
    visited[v1] = true;

    if(v1 == v2){//输出v1到v2的简单路径
        for(int i = 0;i < d;i++){
            printf("%d,"path[i]);
        }
        visited[v2] = 0;//设置目标结点为未访问状态,以便下条路径访问
        return;//由于是找简单路径,v2必不可能在路径之中们只能是路径的终点。所以返回上一层
    }
    struct ArcNode* p = G.vertices[v1].first;//指向邻接边表结点

    while(p){
        int w = p->adjvex;
        if(!visited[w]){
            FindPath(G,w,v2,path,d);
        }
        p = p->next;
    }

    visited[v1] = 0;//恢复顶点的初始状态
}

6.有向无环图的拓扑排序(DFS算法实现)

算法思想:最后的拓扑排序就是递归结束时间从大到小排序所形成的顶点序列

//假设图用邻接表存储
bool visited[MaxVertexNum];//访问标记数组
bool finishedTime[MaxVertexNum];//该数组存储每个顶点完成递归所需的时间,假设完成一层递归时间为1
int time = 0;//记录每个顶点递归完成的时间

void DFSTreaveral(ALGraph G){
    for(int i = 0;i<G.vexNum;i++){
        visited[i] = false;
    }

    for(int i = 0;i < G.vexNum;i++){//从顶点0开始访问
        if(!visited[i]){
            DFS(G,i);
        }
        
    }
}

void DFS(ALGraph G,int v){

    visit(v);
    visited[v] = true;

    struct ArcNode* p = G.vertices[v].first;
    while(p){
        int w = p->adjvex;
        if(!visited[w]){
            DFS(G,w);
        }
        p = p->next;
    }

    time++;
    finishedTime[v] = time;
}

//逆拓扑排序(DFS实现):将访问顶点的操作放在递归函数结束的前一步
void DFSTreaveral(ALGraph G){
    for(int i = 0;i<G.vexNum;i++){
        visited[i] = false;
    }

    for(int i = 0;i < G.vexNum;i++){//从顶点0开始访问
        if(!visited[i]){
            DFS(G,i);
        }
        
    }
}

void DFS(ALGraph G,int v){
   
    visited[v] = true;

    struct ArcNode* p = G.vertices[v].first;
    while(p){
        int w = p->adjvex;
        if(!visited[w]){
            DFS(G,w);
        }
        p = p->next;
    }

   visit(v);
}

5.写出折半查找的递归算法,初始调用时,low为1,high为ST.length

typedef struct{
    ElemType Val[MaxSize]; //0号留空,从1开始存储元素
    int length;
}STable;//待查找有序顺序表的数据结构

int BinSearch(STable ST,ElemType key,int low,int high){

    if(low > high){
        return 0;//递归终止条件
    }

    int mid = (low+high)/2;
    if(ST.Val[mid] > key){
        BinSearch(ST,key,low,mid-1);//前半部分进行二分查找
    }else if(ST.Val[mid] < key){
        BinSearch(ST,key,mid+1,high);//后半部分进行二分查找
    }else{
        return mid;
    }
}

6.使得经常被检索的结点位于表的前端的顺序检索(从前到后一个一个找)策略算法(将被检索的结点与前驱结点进行交换。

①顺序结构实现 :从前到后找,找到指定结点与前面的结点交换位置
int SqSearch(STable arr,ElemType key){
    int temp;
    int i = 0;
    while(arr.Val[i]!=key && i < arr.length);

    if(i < arr.length && i > 0){
        temp = arr.Val[i];
        arr.Val[i] = arr.Val[i-1];
        arr.Val[i-1] = temp;
        return i-1;
    }else{
        return -1;
    }
}

②链式结构实现
LinkList ListSearch(LinkList L,ElemType key){

    if(!L){
        return NULL;
    }

    LinkList curr = L->next,pre = L;
    while(curr && curr->val != key){
        curr = curr->next;
        pre = curr;
    }

    if(pre != L && curr){
        ElemType temp = curr->val;
        curr->val = pre->val;
        pre->val = temp;
    }else{
        return NULL;
    }
}

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-04 01:36:44  更:2022-09-04 01:39:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:53:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码