数据结构第十周itc作业总结

【问题描述】读入n个字符所对应的权值,自底向上构造一棵哈夫曼树,自顶向下生成每一个字符对应的哈夫曼编码,并依次输出。另,求解某字符串的哈夫曼编码,求解某01序列的译码。

【输入形式】输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。第二行中有n个用空格隔开的正整数,分别表示n个字符的权值,依次按照abcd...的默认顺序给出。然后是某字符串和某01序列。

【输出形式】前n行,每行一个字符串,表示对应字符的哈夫曼编码。然后是某字符串的哈夫曼编码,某01序列的译码。

【注意】保证每次左子树比右子树的权值小;如出现相同权值的,则先出现的在左子树,即下标小的在左子树。

【样例输入】

8
5 29 7 8 14 23 3 11

aabchg

00011110111111001

【样例输出】

0001
10
1110
1111
110
01
0000
001

000100011011100010000

acdef

#include <iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#define MAX 1000
using namespace std;
typedef struct halftree
{
           int weight;
           int Lchild;
           int Rchild;
           int parent;
}HalfNode,Halftree[MAX+1];
void Find(Halftree ht,int cur,int &s1,int &s2)//找到没有双亲的最小两个权数
{
           s1=s2=0;
           int min1,min2;
           min1=min2=9999;
           for(int i=1;i<=cur;i++)
           {
                      if(ht[i].parent!=0)
                                 continue;
                      if(ht[i].weight<min1)
                      {
                                 min2=min1;s2=s1;
                                 min1=ht[i].weight;s1=i;
                      }
                      else if(ht[i].weight<min2)
                      {
                                 min2=ht[i].weight;
                                 s2=i;
                      }
           }
}
void CreateHalftree(Halftree ht,int n)//创建哈夫曼树
{
           for(int i=n+1;i<=2*n-1;i++)
           {
                      int s1,s2; typedef char *HalfCode[n+1];
                      Find(ht,i-1,s1,s2);
                      ht[i].weight=ht[s1].weight+ht[s2].weight;
                      ht[i].Lchild=s1;
                      ht[i].Rchild=s2;
                      ht[s1].parent=i;
                      ht[s2].parent=i;
                      ht[i].parent=0;
           }
}
typedef char *HalfCode[MAX+1];
void CreateCode(Halftree ht,HalfCode hc,int n)//创建哈夫曼编码
{
           char *cd;//用来临时储存每一个编码值
           cd=(char*)malloc(n*sizeof(char));
           cd[n-1]='\0';
           for(int i=1;i<=n;i++)
           {
                      int start=n-2;
                      int child=i;int parent=ht[i].parent;
                      while(parent!=0)
                      {
                                 if(ht[parent].Lchild==child)
                                            cd[start--]='0';
                                 else
                                            cd[start--]='1';
                                 child=parent;
                                 parent=ht[child].parent;
                      }
                      hc[i]=(char*)malloc((n-start)*sizeof(char));
                      strcpy(hc[i],&cd[++start]);//注意start要++!!!
                      //cout<<hc[i]<<endl;
           }
           free(cd);
}
void print(HalfCode hc,char ch1[],char ch2[],int n)
{
           for(int i=1;i<=n;i++)
           {
                      cout<<hc[i]<<endl;
           }
           for(int i=0;ch1[i]!='\0';i++)//字母转编码
           {
                      int j=ch1[i]-'a'+1;
                      cout<<hc[j];
           }
           cout<<endl;
           char ch[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
          int j=0;
          while(ch2[j]!='\0')
          {
                     char mid[MAX];
                     int x=0;
                     bool flag=false;
                     for(int i=j;ch2[i]!='\0';i++)
                     {
                                mid[x++]=ch2[i];
                                mid[x]='\0';
                                 for(int y=1;y<=n;y++)
                                {
                                           if(strcmp(hc[y],mid)==0)
                                           {
                                                        cout<<ch[y-1];
                                                        flag=true;
                                                        break;
                                           }
                                }
                                if(flag)
                                {
                                      j=i+1;
                                      break;
                                }
                     }
          }
}
int main()
{
           int n;
           cin>>n;
           Halftree ht;
           for(int i=1;i<=n;i++)
           {
                      int weight;
                      cin>>weight;
                      ht[i].parent=0;
                      ht[i].weight=weight;
           }
           CreateHalftree(ht,n);
          HalfCode hc;
          CreateCode(ht,hc,n);
          char ch1[MAX],ch2[MAX];
          cin>>ch1;
          cin>>ch2;
           print(hc,ch1,ch2,n);
         //  cout<<1<<endl;
}

注释:哈夫曼创建+编码分三步:

1.建立结构体,初始化叶结点(parent=0,输入weight)

2.创建哈夫曼树:贪心最小两个权值自下向上创建树,更新parent和Lchild和Rchild的值

3.编码:用指针数组储存每个字符串编码的头指针。树是自下向上直到根结点,临时字符串是自右向左录入01值,注意start最后要++。

此题必须采用邻接表的存储结构,建立图的存储,然后采用DFS遍历实现求解。否则不给分。

警察抓到了 n 个罪犯,警察根据经验知道他们属于不同的犯罪团伙,却不能判断有多少个团伙,但通过警察的审讯,知道其中的一些罪犯之间相互认识,已知同一犯罪团伙的成员之间直接或间接认识。有可能一个犯罪团伙只有一个人。请你根据已知罪犯之间的关系,确定犯罪团伙的数量。已知罪犯的编号从 1 至 n。

【输入】

第一行:n(<=1000,罪犯数量),第二行:m(<5000,关系数量)以下若干行:每行两个数:I 和 j,中间一个空格隔开,表示罪犯 i 和罪犯 j 相互认识。

【输出】

一个整数,犯罪团伙的数量。

【样例输入】

11

8

1 2

4 3

5 4

1 3

5 6

7 10

5 10

8 9

【输出】

3

#include <iostream>
#include<stdlib.h>
using namespace std;
#define MAX 1000
typedef struct ArcNode//用来表示每个点的邻接点
{
    int adj;
    struct ArcNode *next;
}ArcNode;
typedef struct VertexNode//用来表示每个点
{
    int data;
    ArcNode *first;//每个点的第一个邻接点的指针
}VertexNode;
typedef struct adjlist
{
    VertexNode vertex[MAX+1];
    int vexnum,arcnum;
}AdjList;
int visit[1000]={0};
bool judge(int n)
{
    int s=0;
    for(int i=1;i<=n;i++)
    {
        if(visit[i]==1)
            s++;
    }
    if(s==n)
        return true;
    else
        return false;
}

void DFS(AdjList aj,int v0)//深度搜索
{
   visit[v0]=1;
   ArcNode *p=aj.vertex[v0].first;
   while(p!=NULL)
   {
       if(!visit[p->adj])
       {
           DFS(aj,p->adj);
       }
       p=p->next;
   }
}
void print(AdjList aj,int n)
{
    int v0=1;
    int num=0;
    while(!judge(n))
    {
        DFS(aj,v0);
        for(int i=1;i<=n;i++)
        {
            if(visit[i]!=1)
            {
                v0=i;
                break;
            }
        }
        num++;
    }
    cout<<num<<endl;
}
int main()
{
    int n,m;
    cin>>n;
    cin>>m;
    AdjList aj;
    for(int i=1;i<=n;i++)//初始化邻接表
    {
        aj.vertex[i].first=new ArcNode;
        aj.vertex[i].first=NULL;
    }
    for(int i=1;i<=m;i++)//建立邻接表
    {
        int a,b;
        cin>>a>>b;
        aj.vertex[a].data=a;
        ArcNode *p=NULL;
        ArcNode *q=aj.vertex[a].first;
        p=new ArcNode;
         p->adj=b;
         p->next=NULL;
        if(aj.vertex[a].first==NULL)
        {
            aj.vertex[a].first=p;
        }
        else
        {
            while(q->next!=NULL)
            {
                q=q->next;
            }
            q->next=p;
        }
         aj.vertex[b].data=b;
        ArcNode *pp=NULL,*qq=aj.vertex[b].first;
        pp=new ArcNode;
         pp->adj=a;
         pp->next=NULL;
        if(aj.vertex[b].first==NULL)
        {
            aj.vertex[b].first=pp;
        }
        else
        {
            while(qq->next!=NULL)
            {
                qq=qq->next;
            }
            qq->next=pp;
        }
    }
   // cout<<1<<endl;
    print(aj,n);
}

注释:邻接表+深度搜索遍历图,注意邻接表创建是分配空间问题

根据输入的图的邻接矩阵A,判断此图的连通分量的个数。请使用邻接矩阵的存储结构创建图的存储,并采用BFS优先遍历算法实现,否则不得分。
【输入形式】
 第一行为图的结点个数n,之后的n行为邻接矩阵的内容,每行n个数表示。其中A[i][j]=1表示两个结点邻接,而A[i][j]=0表示两个结点无邻接关系。
【输出形式】
 输出此图连通分量的个数。
【样例输入】
 5
 0 1 1 0 0
 1 0 1 0 0
 1 1 0 0 0
 0 0 0 0 1
 0 0 0 1 0
【样例输出】
 2
【样例说明】
 邻接矩阵中对角线上的元素都用0表示。(单个独立结点,即与其它结点都没有边连接,也算一个连通分量)

#include <iostream>
#include<stdlib.h>
using namespace std;
typedef struct adjmartrix
{
    int arcs[50][50];
    int vexnum;
}AdjMaatrix;
typedef struct queue1
{
    int vex[100];
    int first;
    int last;
}Queue;
int pop(Queue &a)
{
    if(a.first==a.last)
       exit(0);
    else
    {
        a.first++;
        return a.vex[a.first-1];
    }
}
void push(Queue &a,int b)
{
    if(a.last==100)
        exit(0);
    else
    {
        a.vex[a.last]=b;
        a.last++;
    }
}
bool judge(int visit[],int n)
{
    int s=0;
    for(int i=1;i<=n;i++)
    {
        if(visit[i]==1)
            s++;
    }
    if(s==n)
        return true;
    else
        return false;
}
void BFS(AdjMaatrix gn,int n,int v0)//邻接矩阵+广搜遍历图
{
    int visit[n+1];
    for(int i=1;i<=n;i++)
        visit[i]=0;
        visit[v0]=1;
    int num=0;
    while(!judge(visit,n))
    {
        Queue a;
        a.first=a.last=0;
        push(a,v0);
        while(a.first!=a.last)
        {
            int p=pop(a);
            for(int i=1;i<=n;i++)
            {
                if(gn.arcs[p][i]==1&&!visit[i])//两点关联并且没有广搜到过
                {
                    push(a,i);
                    visit[i]=1;
                }
            }
        }
        for(int i=1;i<=n;i++)//查找另外一个连通子图
        {
            if(visit[i]!=1)
            {
                v0=i;
                visit[v0]=1;
                break;
            }
        }
        num++;
    }
    cout<<num<<endl;
}
int main()
{
    int n;
    cin>>n;
    AdjMaatrix gn;
    bool flag=true;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cin>>gn.arcs[i][j];
            if(gn.arcs[i][j]!=0)
                flag=false;
        }

    }
    gn.vexnum=n;
    /*  for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            cout<<gn.arcs[i][j]<<" ";
            cout<<endl;
    }*/
    if(flag)
    {
        cout<<n<<endl;
    }
    else
    BFS(gn,n,1);
    return 0;
}

注释:邻接矩阵+广搜(BFS),邻接矩阵找关联点只需先定行(某个点),再依次遍历每一列(其他点)即可。

【问题描述】
 已知含有n个顶点的带权连通无向图,采用邻接矩阵存储,邻接矩阵以三元组的形式给出,只给出不包括主对角线元素在内的下三角形部分的元素,且不包括不相邻的顶点对。请采用Prim算法,求该连通图从1号顶点出发的最小生成树的权值之和。
【输入形式】
 第一行给出结点个数n和三元组的个数count,以下每行给出一个三元组,数之间用空格隔开。(注意这里顶点的序号是从1到n,而不是0到n-1,程序里要小心!)
【输出形式】
 求解的最小生成树的各条边、边的权值之和
【样例输入】
 5 8
 2 1 7
 3 1 6
 3 2 8
 4 1 9
 4 2 4
 4 3 6
 5 2 4
 5 4 2
【样例输出】

1-3:6
3-4:6
4-5:2
4-2:4
18

【样例说明】
 权值是正整数,可能很大,但不需要考虑整型溢出问题

#include <iostream>

using namespace std;
#define MAX 20//点的最大个数
int judge[MAX]={0};
typedef struct arcnode
{
    int adj;//权值
} ArcNode;
typedef struct adjmatrix
{
    ArcNode arcs[MAX][MAX];
    char vertex[MAX];
    int vexnum,arcnum;
}AdjMatrix;
struct
{
    int adjvex;
    int lowcost;
}closedge[MAX+1];
int Min(AdjMatrix gn)
{
    int min=25897;
    int c;
    for(int i=1;i<=gn.vexnum;i++)
    {
        if(min>closedge[i].lowcost&&closedge[i].lowcost!=0)
        {
             min=closedge[i].lowcost;
             c=i;
        }
    }
    return c;
}
void Mintree(AdjMatrix gn,int u)
{
    int sum=0;
    closedge[u].lowcost=0;//初始化U={u}
    for(int i=1;i<=gn.vexnum;i++)//先把起点与各点关系以及距离记录下来
    {
        if(i!=u)//防止重复
        {
            closedge[i].adjvex=u;//表示将两个点关联,i点与u点关联
        closedge[i].lowcost=gn.arcs[u][i].adj;//表示u,i之间的距离(权值)
        }
    }
    for(int e=1;e<=gn.vexnum-1;e++)
    {
        int v=Min(gn);
        u=closedge[v].adjvex;
        cout<<u<<"-"<<v<<":";
        cout<<closedge[v].lowcost<<endl;
        sum+=closedge[v].lowcost;
        closedge[v].lowcost=0;
        for(int i=1;i<=gn.vexnum;i++)
        {
            if(gn.arcs[v][i].adj<closedge[i].lowcost)
            {
                closedge[i].lowcost=gn.arcs[v][i].adj;
                closedge[i].adjvex=v;
            }
        }
    }
    cout<<sum<<endl;
}
int main()
{
    int n,Count;
    cin>>n>>Count;
    AdjMatrix gn;
    gn.vexnum=n;
    gn.arcnum=Count;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            gn.arcs[i][j].adj=25378;
        }
    }
    for(int i=1;i<=Count;i++)
    {
        int u,v,weight;
        cin>>u>>v>>weight;
        gn.arcs[u][v].adj=weight;
        gn.arcs[v][u].adj=weight;
    }
    /*for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<gn.arcs[i][j].adj<<" ";
        }
        cout<<endl;
    }*/
    Mintree(gn,1);
    return 0;
}


注释:普利姆算法求最小子树

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值