DS博客作业05--查找

0.PTA得分截图

1.本周学习总结(0-4分)

1.1 总结查找内容

  • 查找的性能指标ASL
    查找表分为动态查找表和静态查找表,动态查找表是在查找的同时对表有修改的操作,静态查找表没有修改的操作;查找又分为在内存中进行的内查找和需要访问外存的外查找。在查找时,主要是和关键字进行比较,把和关键字进行比较的平均次数称为平均查找长度ASL

    n是元素总个数,Pi是第i个元素被找到的概率,Ci是第i个元素被找到的比较次数。ASL分为成功的ASLsuc和不成功的ASLunsuc。
    静态查找表的结构体
typedef int KeyType;
typedef struct
{
   KeyType key;
   InfoType data;
}RecType;

ASL是衡量一个算法好坏的重要指标,ASL越大,说明查找时间性能越差。

  • 顺序查找
    顺序查找是最简单的一种查找方法,就是从表头一直到表尾和给定值进行比较,代码如下
int SeqSearch(RecType R[],int N,KeyType k)
{
   int i=0;
   while(i<n&&R[i].key!=k)  i++;
   if(i>=n) return 0;
   else return i+1;
}

因此顺序表成功时的平均查找长度为

若查找不成功,要进行n次比较才能确定查找不成功,所以ASL不成功=n。

  • 二分查找
    二分查找又称折半查找,它需要查找表是一个有序表,基本思路就是设初始low为0,high为n-1,mid=(low+high)/2,以这三个变量为下标,要查找的值为k,若k=R[mid].key,则查找成功;若k>R[mid].key,则使low=mid+1;若k<R[mid].key,则使high=mid-1,重复此过程,直到low>high。代码如下
int BinSearch(RecType R[],int n,KeyType k)
{  int low=0,high=n-1,mid;
   while (low<=high) //当前区间存在元素时循环
   {	mid=(low+high)/2;
	if (R[mid].key==k)//查找成功	                  
           return mid+1;
	if (k<R[mid].key)	
	   high=mid-1;
	else
	   low=mid+1;
   }
   
   return 0;
}

二分查找的过程可以用二叉树来表示,称为二分查找的判定树或比较树,查找成功时对应的结点称为内部结点,不成功时称为外部结点,其形态只与表的元素个数n有关。所以平均查找长度为

下面举个例子

查找成功就是找到圆形结点

查找不成功就是找到方形结点

  • 动态查找:二叉搜索树。
    二叉排序树又称二叉搜素树,它满足以下几条性质:1.若根结点的左子树不为空,则左子树上所有的关键字都小于根结点的关键字;2.若根结点的右子树不为空,则右子树上所有的关键字都小于根结点的关键字;3.根结点的左右子树也同样符合1.2条件。二叉搜素树还有一个特点,就是中序遍历后,会得到一个递增有序序列。结构体定义如下
typedef struct node
{
     KeyType key;
     InfoType data;
     struct node *lchild,*rchild;
}BSTNode;

二叉搜索树的查找,从根节点开始,先序遍历的方式依次和要查找的值进行比较。

BSTNode *SearchBST(BSTNode *bt,KeyType k)
 {  if (bt==NULL || bt->key==k)//递归终结条件
       return bt;
    if (k<bt->key)
       return SearchBST(bt->lchild,k);//在左子树中查找
    else
       return SearchBST(bt->rchild,k);//右子树中查找
 }

二叉搜素树的插入和建立,二叉搜索树的建立也就是不断的进行插入操作,边插边建,插入过程为:当二叉搜索树是空树时,则建立一个根结点,然后再让根结点和要插入的数据进行比较,若根结点的关键字小于要插入的数据,则插在根结点的右子树上,否则插在左子树上。

int InsertBST(BSTree &p,KeyType k)//二叉搜索树的插入
{  if (p==NULL)	 //原树为空   
   {      
       p=new BSTNode;
       p->key=k;p->lchild=p->rchild=NULL;
       return 1;
   }
   else if  (k==p->key) //相同关键字的节点0
       return 0;
   else if (k<p->key) 
       return InsertBST(p->lchild,k);//插入到左子树
   else  
       return InsertBST(p->rchild,k);//插入到右子树
}
BSTNode *CreatBST(KeyType A[],int n) //二叉搜索树的建立,返回树根指针
{      BSTNode *bt=NULL;    //初始时bt为空树
       int i=0;
       while (i<n) 
       {    
         InsertBST(bt,A[i]);  //将A[i]插入二叉排序树T中
       i++;
       }
       return bt; //返回建立的二叉排序树的根指针
} 

二叉搜索树的删除,在删除过程中,要保证每次删除后的二叉树还能保持BST的性质,删除过程分为以下几种情况:1.若删除结点为叶子结点,则直接删除该结点;2.若删除结点只有左子树,没有右子树,则直接将其左孩子代替它;3.若删除结点只有右子树,没有左子树,则直接将其右孩子代替它;4.若删除结点既有左子树又有右子树,则将其左子树中的最大关键字的结点的值替换要删除的结点的值,然后删除最大关键字的结点。

int DeleteBST(BSTree &bt,KeyType k)	
{  if (bt==NULL) return 0;//空树删除失败
   else 
   { 
      if (k<bt->key) return DeleteBST(bt->lchild,k);//递归在左子树中删除为k的节点
      else if (k>bt->key) return DeleteBST(bt->rchild,k);//递归在右子树中删除为k的节点
      else 
      {    Delete(bt);//删除*bt节点
	   return 1;
      }
  }
} 
void Delete(BSTreee &p)//从二叉排序树中删除*p节点
{  BSTNode *q;
   if (p->rchild==NULL)//*p节点没有右子树的情况
   {   
     q=p; p=p->lchild;delete q; 
   }
   else if (p->lchild==NULL)//*p节点没有左子树
   {    q=p; p=p->rchild;delete q; 

   }
   else Delete1(p,p->lchild);//*p节点既有左子树又有右子树的情况
}
void Delete1(BSTNode *p,BSTNode *&r)//被删节点:p,p的左子树节点:r
{  BSTNode *q;
   if (r->rchild!=NULL)
	  Delete1(p,r->rchild); //递归找最右下节点
   else //找到了最右下节点*r
   {    
      p->key=r->key;
      q=r; r=r->lchild;delete q; //将*r的关键字值赋给*p
   }
}
  • AVL树的定义及4种调整做法
    AVL树也就是平衡二叉树,若一棵二叉搜索树中的每个结点的左右子树的高度差都小于等于1,则称这个二叉树为平衡二叉树,所以定义平衡因子来衡量是否是平衡二叉树,平衡因子就是结点的左子树高度减去右子树高度所得的差,当平衡因子的绝对值小于等于1时,则为AVL树。向AVL树中插入一个新结点可能会破坏平衡,这时则需要进行调整,把失衡的最小子树调整为平衡子树,失衡的最小子树是指以离插入结点最近且平衡因子的绝对值大于1的结点为跟的子树。进行调整时,分为四种情况:1.LL调整;2.RR调整;3.LR调整;4.RL调整。
    1.LL调整:这类调整是因为A结点的左孩子B的左子树上插入结点而导致的不平衡,调整方法一般为将B结点向上升从而替代A结点作为根结点,A结点作为B结点的右孩子,B结点原来的右子树作为A结点现在的左子树。
    2.RR调整:这是因为A结点的右孩子B的右子树上插入结点而导致的不平衡,调整方法和LL调整类似,将B结点向上升替代A结点作为根结点,A结点作为B结点的左孩子,B结点原来的左子树作为A结点现在的右子树。
    3.LR调整:这个是因为在A结点的左孩子B的右子树上插入结点C造成的不平衡,调整方法是把C结点上升作为根结点,B结点作为C结点的左孩子,A结点作为C结点的右孩子,C结点原来的左子树作为B结点的右子树,C结点原来的右子树作为A结点的左子树。
    4.RL调整:是由于A结点的右孩子B的左子树上插入结点C造成的不平衡,调整方法和LR调整基本一样,把C结点上升作为根结点,A结点作为C结点的左孩子,B结点作为C结点的右孩子,C结点原来的左子树作为A结点的右子树,C结点原来的右子树作为B结点的左子树。
  • B-树和B+树定义
    B-树中的所有结点的孩子结点的最大值是B-树的阶,用m表示,也就是所有结点中有最多分支数的那个结点有m个分支。一棵m阶B-数或者是空树,或者是满足下列要求的m叉树:1.树中的每个结点最多有m个分支,每个结点最多有m-1个关键字;2.根结点最少有两棵子树;3.除根结点外,非叶子结点最少有m/2的上界棵子树,最少有m/2的上界-1个关键字;4.每个结点的结构为

    n为结点的关键字个数,Ki是关键字值,Pi是孩子结点的指针;5.所有外部结点都在同一层,不带任何信息。如果一棵B-树有n个关键字,则外部结点的个数为n+1个。结构体定义如下
#define MAXM 10		  //定义B-树的最大的阶数
typedef int KeyType;    //KeyType为关键字类型
typedef struct node      //B-树节点类型定义
{  int keynum; 	  //节点当前拥有的关键字的个数
   KeyType key[MAXM];  //[1..keynum]存放关键字,[0]不用
   struct node *parent;	    //双亲节点指针
   struct node *ptr[MAXM];//孩子节点指针数组[0..keynum]
} BTNode;
//m,Max,Min为全局变量
int m;//m阶B-树
int Max;//m阶B-树结点的最多关键字个数
int Min;//m阶B-树结点的最少关键字个数

B+树和B-树类似,但一棵m阶B+树满足以下条件:1.每一个分支结点最多有m棵子树;2.根结点要么没有子树,要么最少有两棵子树;3.除根结点外,其他结点最少有m/2的上界棵子树;4.有n个分支的结点有n个关键字;5.叶子节点中有全部关键字及指向相应记录的指针,按关键字大小顺序链接;6.所有的分支结点中仅包含它的各个子结点中的最大关键字和指向子结点的指针。
B-树的插入:1.找出关键字K的插入结点,该插入结点一定是某个叶子结点;2.在插入结点中插入关键字K,同时还要判断插入的结点是否还有空位置,即关键字个数是否小于Max,此时分两种情况:①当插入结点的关键字个数小于Max时,直接将关键字K插入到结点中,并保持有序;②当插入结点的关键字个数等于Max时,要把该结点进行分裂,分裂做法是再创建一个新结点,在中间位置把关键字分成两部分,左边放在旧结点中,右边放入新结点中,中间位置的关键字插入到双亲结点中,如果双亲结点关键字个数大于Max,则再进行分裂。
B-树的删除:删除结点分为两种情况,一种是删除叶子结点,一种是删除非叶子结点。当删除非叶子结点时,设要删除的非叶子结点的关键字k=key[i],用该结点ptr[i-1]所指子树中的最大关键字或者最小关键字来替代要删除的关键字,然后再删除子树中的最大或最小关键字;当删除叶子结点时,有以下三种情况:1.若删除结点的关键字个数大于Min,则直接删除该关键字;2.如果删除结点的关键字个数等于Min,这时要向兄弟结点借关键字,若该结点的兄弟结点中的关键字个数大于Min,则把兄弟结点中最大或最小的关键字移到双亲结点中,然后把双亲结点中大于或小于上移关键字的那个关键字下移到要删除的关键字的结点中;若该结点的兄弟结点中的关键字个数都为Min,则需要进行合并,把要删除关键字的结点与左兄弟或者右兄弟结点和双亲结点中分割二者的关键字合并成一个结点,如果双亲结点中的关键字个数也小于Min,则对双亲结点进行同样的处理。
下面举个例子,在下图中的B-树里依次插入30,26,85,7,然后再删去50,53,37

插入关键字30:

插入关键字26:

插入关键字85:


插入关键字7:

删去关键字50:

删去关键字53:

删去关键字37:

  • 散列查找
    哈希表又称散列表,是一种存储线性表的存储结构,它的基本思路就是设要存储的元素个数为n,长为m(m>=n)的连续内存单元,以关键字为自变量,通过哈希函数映射到内存单元的地址,把该元素存储在这个内存单元中。当两个关键字不同时,但哈希地址相同,这时称为哈希冲突,把这两个元素称为同义词。哈希查找性能与三个因素有关:1.装填因子,即哈希表中的元素个数n与长度m的比值,装填因子越小,冲突的可能性越小。2.所采用的哈希函数。3.解决哈希冲突的方法。
    哈希函数的构造方法一般有:1.直接地址法,以关键字本身或者关键字加上某个数C作为哈希地址,则哈希函数为h(k)=k+c。2.除留余数法,用关键字k除以某个整数p,且p小于等于哈希表长度,所得的余数作为哈希地址,哈希函数为h(k)=k mod p (p<=m),这个方法容易出现哈希冲突。
    哈希冲突的解决方法主要有开发地址法和拉链法,开发地址法就是当出现哈希冲突时,在哈希表中再找一个新的空位置存放元素,这个方法又分为线性探测法和平方探测法,线性探测法是在发生冲突的地址开始,依次探测下一个地址,直到出现一个空位置为止,公式为d0=h(k),di=(di-1+1) mod m (1≤i≤m-1);平方探查法的公式为:d0=h(k),di=(d0± i^2) mod m (1≤i≤m-1) 查找的位置依次为:d0、d0 +1、d0 -1、d0 +4、d0 -4……。拉链法是把同义词用单链表下形式链接起来,如图所示

    哈希表的构造方法
    开发地址法创建哈希表,结构体定义如下
#define NULLKEY -1  //定义空关键字
#define DELKEY -2 //定义被删关键字
typedef int KeyType; //关键字类型
typedef struct
{
    KeyType key;  //关键字域
    int count;  //探测次数域
}HashTable;  //哈希表单位类型

哈希表的插入和建表如下

int InsertHT(HashTable ha,int p,int k,int &n)
{
    int adr,i;
    adr=k % p;
    if(adr==NULLKEY || adr==DELKEY)    //地址为空,可插入数据
    { 
       ha[adr].key=k;ha[adr].count=1;
    } 
    else
    {
        i=1;
        while(ha[adr].key!=NULLKEY && ha[adr].key!=DELKEY)
        {    
           adr=(adr+1) % m; 
           i++;
        }//查找插入位置
        ha[adr].key=k;ha[adr].count=i;   //找到插入位置 
    }
    n++;
}
void CreatHT(HashTable ha,int &n,int m,int p,KeyType keys[],int nl)
{
    for(int i=0;i<m;i++
    {
       ha[i].key=NULLKEY;
       ha[i].count=0;
    }
    n=0;
    for(i=0;i<nl;i++)
        InsertHT(ha,p,keys[i],int &n);
}

哈希表的ASL计算

当成功时,ASL计算查找到哈希表中已有关键字的平均探测次数


当不成功时,假设查找m对应哈希地址为adr,查找h(adr),查找不成功2种可能:1.h(adr)==NULL,探测一次;2.h(adr)≠NULL,但是h(adr)!=key,继续探测adr++,直到h(adr)=NULL。

用拉链法构造哈希表,称为哈希链,是一种顺序和链式相结合的存储结构,结构体定义如下

typedef int KeyType;  //关键字类型
typedef struct node
{
    KeyType key;     //关键字域
    struct node*next;     //下一个结点指针
}NodeType;      //单链表结点类型
typedef struct
{
    NodeType *firstp;       //首结点指针
}HashTable;     //哈希表单元类型

拉链法建哈希表的插入建表

void InsertHT(HashTable ha[],int &n,int p,KeyType k)  //将关键字k插入到哈希表中
{
    int adr;
    adr=k%p;   //计算哈希函数值
    NodeType *q;
    q=(NodeType*)malloc(sizeof(NodeType));
    q->key=k;  //创建一个结点q,存放关键字k
    q->next=NULL;
    if(ha[adr].firstp==NULL)
        ha[adr].firstp=q;
    else      //若单链表adr不为空
    {
        q->next=ha[adr].firstp;  //采用头插法插入到ha[adr]的单链表中
        ha[adr].firstp=q;
    }
    n++;   //哈希表中结点的总个数增1
}
void CreatHT(HashTable ha[],int &n,int m,int p,KeyType keys[],int nl)  //由关键字序列keys[0..nl-1]创建哈希表
{
    for(int i=0;i<m;i++)         //哈希表置初值
        ha[i].firstp=NULL;
    n=0;
    for(i=0;i<nl;i++)
        InsertHT(ha,n,p,keys[i]);     //插入n个关键字
}

哈希链的ASL计算

当查找成功时,比较次数就是该结点属于一个单链表的第几个结点,所以有

当不成功时,若第d个单链表有i个结点,则需要比较i次才能确保查找失败,所以有

1.2.谈谈你对查找的认识及学习体会。

对查找主要学了线性表查找、树表查找以及哈希表的查找。线性表查找主要是顺序查找、折半查找和分块查找,树表查找主要是二叉排序树、AVL树、B-树和B+树,哈希表查找主要是开发地址法建哈希表查找和拉链法建哈希表查找。无论哪种查找,都要涉及插入、创建、删除、查找和计算成功和不成功的ASL等操作。学习完查找之后,发现有这么多的查找方法,方便了以后从一系列数据中查找某个数据的过程,感觉难度和树、图都差不多。查找算法可以广泛应用到各种搜索引擎上,也可以用于用户查找个人信息等。

2.PTA题目介绍(0--6分)

2.1 7-1 是否完全二叉搜索树(2分)

2.1.1 该题的设计思路

本题是有关二叉搜索树的一道题,有两个概念,一个是完全二叉树,一个是二叉搜索树,完全二叉树的特点是叶子结点的上一层是满的,并且没有结点是有右孩子而无左孩子的,二叉搜索树的特点是所以结点的左孩子都比根结点小,右孩子都比根结点大,但本题给定的条件是相反的,所以要注意这一点。本题问题就是给你一组数据,让你建一棵二叉搜索树,然后判断是否是完全二叉搜索树。
基本思路就是建好树之后就层次遍历,当遍历到空结点的时候,赋值为-1给一个数组,其他结点的数据原样赋给一个数组,最后遍历数组,看是否有在出现小于0后又出现大于0的情况,若有,则输出NO,否则输出YES。时间复杂度为O(n)。

2.1.2 该题的伪代码

#define NULLNODE -1  //子树为空时
//结构体定义
/*typedef int ElementType;
typedef struct TNode* Position;
typedef Position BinTree;
struct TNode {
	ElementType Data;
	BinTree Left;
	BinTree Right;
};*/

int main()
{
	for (i从0到N-1)//N为输入的数据个数
		输入数据
		插入到树中T = Insert(T, a[i]);
        end for
	层次遍历结果levelPrint(T);
	判断是否是完全二叉搜素树Judge(T);
}
BinTree Insert(BinTree BST, int x)
{
	当BST为空时,建立根结点
                BST = (BinTree)malloc(sizeof(struct TNode));
		BST->Data = x;
		BST->Left = BST->Right = NULL;
	如果插入数据比该结点大,则插入到左子树Insert(BST->Left, x);
        如果插入数据比该结点小,则插入到右子树Insert(BST->Right, x);
	返回根结点BST;
}
void levelPrint(BinTree BST)
{
	定义队列qu,根结点进队qu.push(BST);
	while (队不为空时)
		取队首BT = qu.front();
		输出数据,然后出队qu.pop();
		若左孩子不为空,左孩子进队qu.push(BT->Left);
		若右孩子不为空,右孩子进队qu.push(BT->Right);
	end while
}
void Judge(BinTree BST)
{
	定义赋值数组judge[100]
	定义队列q,根结点入队q.push(BST);
	存入数据judge[i++] = BST->Data;
	while (队不空时)
		取队首bt = q.front();出队q.pop();
		若左孩子为空,右孩子不为空
			存入数据judge[i++] = NULLNODE;
			不为空的孩子进队q.push(bt->Right);
			存入数据judge[i++] = bt->Right->Data;
		若左孩子不为空,右孩子为空
			不为空的孩子进队q.push(bt->Left);
			存入数据judge[i++] = bt->Left->Data;
			存入数据judge[i++] = NULLNODE;
		若左右孩子都为空
			存入两次数据judge[i++] = NULLNODE;
	        否则
			若左孩子不为空,进队q.push(bt->Left);
			存入数据judge[i++] = bt->Left->Data;
			若右孩子不为空,进队q.push(bt->Right);
			存入数据judge[i++] = bt->Right->Data;
        end while
	遍历数组judge,根据层次遍历的特点,即一层一层的依次遍历,输出是否是完全二叉搜索树
}

2.1.3 PTA提交列表


这道题整体上并没有遇到太大的问题,除了判断的那个函数Judge(),写这个函数的时候不知道该怎么存入结点为空时的数据,后来想了很久,也没有想到比较简单的写法,于是就按笨方法,分条件讨论,然后存入到一个数组中,再根据层次遍历特点访问数组,判断是否是完全二叉搜索树。第一个问题就不说了,出现了段错误,是因为定义树的时候没有给初值NULL,赋了初值NULL后就对了。

2.1.4 本题设计的知识点

本题主要学习了二叉搜索树的建立,是边插边建,然后又复习了树的层次遍历,要借助队列。最后在判断的时候,知识点就是二叉搜索树左子树比根结点小,右子树比根结点大,但本题是正好相反,性质都一样,还有就是层次遍历的特点,依次一层一层的遍历结点。

2.2 7-4 整型关键字的散列映射(2分)

2.2.1 该题的设计思路

该题主要意思就是建一个哈希表,然后再找各个数据在表中的地址,可定义一个哈希数组来表示哈希表,其中的数据用结构体表示。在构造哈希函数时,用除留余数法h(k)=k mod p,在解决哈希冲突时,用线性探测法di=(di+1) mod m。此题的哈希表长度刚好和除数相同,也就是说m和p相等,p最好取素数。基本思路就是建哈希表,边插边建表,插入时看是否为空地址,然后看是否需要重新取地址,在查找时,要同时满足两个条件,即地址存在,且该地址的关键字就是要查找的元素。时间复杂度为O(n)。

2.2.2 该题的伪代码

#define MaxSize 1009	//定义最大哈希表长度
#define NULLKEY -1	//定义空关键字值

//结构体定义
/*typedef int KeyType;		//关键字类型
typedef struct node
{
	KeyType key;			//关键字域
} HashTable[MaxSize];		//哈希表类型
*/

int main()
{
	for (i从0到N-1)//N为输入的数据个数 
	    输入数据
        end for
	创建哈希表CreateHT(ha, H, N, P);
	
	for (i从0到N-1)
	    进行查找数据地址,返回地址给一个变量,j = SearchHT(ha, P, H[i]);
	    输出地址j
	end for
}
void InsertHT(HashTable ha, int& n, KeyType k, int p)//哈希表插入数据
{
	取哈希函数地址adr = k % p;
	若地址为空,插入数据
	否则
            while (某个地址不为空并且关键字不等于k时)
		重新取地址adr = (adr + 1) % p;
            end while
	    插入数据 
}
void CreateHT(HashTable ha, KeyType x[], int n, int p) //创建哈希表
{
	for (i从0到p-1)//p为哈希表长度
            初始化哈希表为NULLKEY
        end for
	for (i从0到n-1)//n为数据个数
	    插入数据InsertHT(ha, n, x[i], p);
}
int SearchHT(HashTable ha, int p, KeyType k)//在哈希表中查找关键字k
{
	取地址adr = k % p;
	while (地址不为空且关键字不等于k时)
	      探查下一个地址adr = (adr + 1) % p; 
        end while
	找到关键字时,返回该关键字的地址,否则返回-1
}

2.2.3 PTA提交列表


虽然提交列表有点长,但都是一个问题,就是那个最大N随机的测试点,一直没有明白意思,我以为是MaxSize设的有问题,然后改了又改都不对,又来来回回检查了好几遍其他地方,都不知道有什么问题。最后问了一下黄嘉欣,然后才知道问题出现在了哪,就是输入重复数据时,地址要一样,也就是说第一个重复数据可以插入到哈希表中,但其他的与该数据重复的不能再插入表中了,比如24 15 15 88,这四个数据,只能插入3个数据到哈希表中,即24 第一个15 88,所以在插入函数代码中改了一下循环条件就对了。

2.2.4 本题设计的知识点

该题的知识点就是怎么建哈希表,在建哈希表时怎么选项哈希函数,怎么解决哈希冲突。我们可以用除留余数法来构造哈希函数,即h(k)=k mod p,在解决哈希冲突时,用开放地址法,就是线性探测法,即d0=h(k) di=(d(i-1) +1) mod m。

2.3 7-3(map) QQ帐户的申请与登陆(2分)

2.3.1 该题的设计思路

该题是一个关于qq账号密码申请登陆的相关应用,就是根据输入的数据,判断是否是新账号,和申请账号密码。主要思路就是利用map容器,来存放账号密码,然后再和后面输入的账号密码进行比较,如果还没有存放,则存放进去,若已经存放,即为老用户,再判断输入的账号密码是否是正确的。时间复杂度为O(n)。

2.3.2 该题的伪代码

int main()
{
	定义map型变量map<string, string>str;
	while (当N不为0时)//N为输入的指令总数
		输入一行数据
		若为老用户
		    若老帐户QQ号码不存在,则输出“ERROR: Not Exist”
		    若老帐户登陆成功,则输出“Login: OK”
		    若老帐户密码错误,则输出“ERROR: Wrong PW”
		否则是新用户
		    若新用户的账号还没有存入,则输出“New: OK”,并且把账号密码存入str中
		    若新申请的号码已经存在,则输出“ERROR: Exist”
	end while
}

2.3.3 PTA提交列表


本题是一遍过的,但在此之前,因为题目中有提示用map做,所以查了一下map的用法,于是就写了一个map<string,string>str这条语句,用来存账号密码,然后根据不同条件来输出不同的结果。提交之后,发现耗时和内存非常大,但暂时我还没有改进的方法,后续我尽量改进改进。

2.3.4 本题设计的知识点

本题的知识点主要就是学会利用map容器来解决各种问题,有map<int,int>,map<int,string>,map<char,char>等,要选择合适的map来解决不同的问题。

posted on 2020-05-24 19:38  王威。  阅读(359)  评论(0编辑  收藏  举报

导航