一、2019年B:
41、 设计一算法,从顺序表中删除最小值的元素(设顺序表中元素均不相同)。空出的位置由最后一个元素填补,若顺序表为空则显示出错信息并退出运行。
/*
设计一算法,从顺序表中删除最小值的元素(设顺序表中元素均不相同)。
空出的位置由最后一个元素填补,若顺序表为空则显示出错信息并退出运行。
*/
//若删除成功,则返回true;否则返回false
bool del_Min(sqList &L){
if(L.length==0)
return false; //表空,返回false
minValue = L.data[0];//假定0号元素的值最小
int minValueIndex = 0;
for(int i=1;i<L.length;i++) //循环,寻找具有最小值得元素
if(L.data[i] < minValue){
minValue = L.data[i];
minValueIndex = i;
}
L.data[minValueIndex] = L.data[L.length-1]; //空出的元素由最后一个元素填补
L.length--;
return true; //此时,value为最小值
}
扩展功能:假设无序状态
先对链表进行排序在删除数相等的结点
void sortDel() //排序+删除
{
pStu p, q, temp1;
int temp;
p = head;
for( p ; NULL != p->Next ; p = p->Next )
{
for( q = p->Next ; NULL != q->Next ; q = q->Next)
{
if( p->Next->a > q->Next->a )
{
temp = p->Next->a;
p->Next->a = q->Next->a;
q->Next->a = temp;
}
}
}
/************以上是排序,下面是去重**********************/
p = head->next;
q = p->next;
while(NULL != q)
{
if(p->a == q->a)
{
temp1 = q;
p->next = q->next;
q = q->next;
delete(temp1);
}
else
{
q = q->next;
p = p->next;
}
}
}
/**
已知一个队列 Q,其结点的数据域为一个自然数。输入一个自然数
n,与队头结点数据配对。如果相等,则删除队头结点;如果不相等或队列为空,
则把 n 插入队列。如果输入数为 0,则结束处理
队列的 ADT 函数有:
void enQueue(Queue q,ElemType e); //元素 e 入队
ElemType deQueue(Queue q,ElemType e); //出队,将队头元素放入 e
int isEmpty(Queue q); //判断队空,返回值是1表示队空,返回值0表示非空
void GetHead(Queue q, ElemType x);//获取队首元素,放入 x
*/
//输入数据为n
void dealQ(Queue q,int n)
{
if(n == 0)
{
return 0;//如果输入数为 0,则结束处理
}
if(isEmpty(q)){
ElemType s;
s.data = n;
enQueue(&q,s);
return;
}
ElemType frontNode;
GetHead(&q,&frontNode);
if(frontNode.data == n)//如果相等
{
//删除队头节点
deQueue(&q,&frontNode);
}
else
{
ElemType s;
s.data = n;
enQueue(&q,s);
}
}
/*
设非空二叉树采用二叉链表存储结构,根结点的指针为 bt。试利用二叉树
的中序遍历,编写判断该二叉树是否为二叉排序树的非递归算法。
*/
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Checker {
public:
bool checkBST(TreeNode* root)
{
stack<TreeNode*>tmpStack;
TreeNode* pNode=root;
int minVal=-1000;//初始化一个最小值;
if (root==NULL)
{
return 1;//空树是二叉排序树;
}
else
{
while(pNode||!tmpStack.empty())
{
while(pNode)
{
tmpStack.push(pNode);//左孩子入栈;
pNode=pNode->left;
}
if (!tmpStack.empty())
{
if (minVal>tmpStack.top()->val)
{
return 0;
}
minVal=tmpStack.top()->val;
pNode=tmpStack.top()->right;
tmpStack.pop();//出栈;
}
}
return 1;
}
}
};
二、2020年B:
/*
41、(20 分)如下描述一个集合的抽象数据类型 ASet,其中所有元素为正整
数,集合的基本运算包括:
(1)由整数数组a[0..n-1]创建一个集合。createset( &s,a,n): (5分) ( ○ 44 )
(2)输出一个集合的所有元素。dispset( s):(5 分)( ○ 45 )
(3)判断一个元素是否在一个集合中。inset(s,e):(5 分)( ○ 46 )
(4)求两个集合的并集。void add(s1,s2,s3):s3=s1∪s2 (5 分)( ○ 47 )
在此基础上设计了集合的顺序存储结构,请写出实现各基本运算的算法。
ADT ASet
{
数据对象:D={ di | 0≤i≤n,n 为一个正整数}
数据关系:无。
基本运算:
createset( &s,a,n):创建一个集合 s;
dispset( s):输出集合 s;
bool inset(s,e):判断 e 是否在集合 s 中
void add(s1,s2,s3):s3=s1∪s2; //求集合的并集
}
设计集合的顺序存储结构类型如下:
typedef struct //集合结构体类型
{
int data[MaxSize]; //存放集合中的元素,其中 MaxSize 为常量
int length; //存放集合中实际元素个数
} Set; //将集合结构体类型用一个新类型名 Set 表示
*/
#include<iostream>
using namespace std;
const int MaxSize = 100;
typedef struct //集合结构体类型
{
int data[MaxSize]; //存放集合中的元素,其中 MaxSize 为常量
int length; //存放集合中实际元素个数
} Set;
class ASet
{
private:
int D[];
public:
void createset(Set &s,int a[],int n);
void dispset(Set s);
bool inset(Set s,int e);
void add(Set s1,Set s2,Set &s3);
};
void ASet::createset(Set &s,int a[],int n)
{
if(n > MaxSize)
{
throw "数组元素过长,溢出异常";//抛异常
}
for(int i = 0;i < n;i++)
{
s.data[i] = a[i];
}
s.length = n;
}
void ASet::dispset(Set s)
{
for(int i = 0;i < s.length;i++)
{
cout<<s.data[i]<<endl;
}
}
bool ASet::inset(Set s,int e)
{
for(int i = 0;i < s.length;i++)
{
if(e == s.data[i])
{
return true;
}
else{
return false;
}
}
}
void ASet::add(Set s1,Set s2,Set &s3)
{
int index = 0;
s3.length = 0;
bool flag = true;
for(int i = 0;i < s1.length;i++)
{
for(int j = 0;j < s3.length;j++)
{
if(s3.data[j] == s1.data[i])
{
flag = false;
break;
}
}
if(flag)
{
s3.length++;
s3.data[index++] = s1.data[i];
}
flag = true;//要进行重置
}
for(int i = 0;i < s2.length;i++)
{
for(int j = 0;j < s3.length;j++)
{
if(s3.data[j] == s2.data[i])
{
flag = false;
break;
}
}
if(flag)
{
s3.length++;
s3.data[index++] = s2.data[i];
}
flag = true;//要进行重置
}
}
int main()
{
ASet aset;
Set s;
int arr[] = {12,3,2,9,7,8};
aset.createset(s,arr,6);
aset.dispset(s);
cout<<aset.inset(s,15)<<endl;
//其他测试
cout<<"*******************"<<endl;
Set s1,s2,s3;
int arr1[] = {1,3,5,7,9,8};
int arr2[] = {2,4,6,8,10,12};
aset.createset(s1,arr1,6);
aset.createset(s2,arr2,6);
aset.add(s1,s2,s3);
aset.dispset(s3);
return 0;
}
/*
42、(8 分)以二叉链表作为二叉树的存储结构,编写统计二叉树的叶结点
个数算法。( ○ 48 )----->参考19B有个题
*/
#include<iostream>
using namespace std;
int ans; //叶子节点数
typedef struct biTnode{
char data;
struct biTnode *lc,*rc;
}biTnode,*bitree;
void cr_bitree(bitree &T)
{//先序建树
char ch;
cin>>ch;
if(ch=='#') T = NULL;//空树
else{
T= new biTnode;//ch!='#',建节点
T->data = ch;
cr_bitree(T->lc);// 左子树
cr_bitree(T->rc);// 右子树
}
}
void find(bitree T)
{
if(T==NULL) return;//节点为空不计入
if(T->lc==NULL&&T->rc==NULL)
ans++;//当且仅当左右孩子为空,节点date不为空时,ans++;
else
{
find(T->lc);//找左树(左孩子)
find(T->rc);//找右树(右孩子)
}
}
int main()
{
ans=0;
bitree T;
cr_bitree(T);
find(T);
cout<<ans<<endl;
delete T;
return 0;
}
/*
43、(12 分)如果允许在循环队列的两端都可以进行插入和删除操作。要求:
① 写出循环队列的类型定义;(4 分)( ○ 49 )
② 写出“从队尾删除”和“从队头插入”的算法。(8 分)( ○ 50 )
*/
#include<iostream>
using namespace std;
const int QueueSize=100;
class CirQueue
{
public:
CirQueue() //构造函数,置空队列
{
front = rear = 0;
}
~CirQueue(){cout<<"destory";} //析构函数
void EnQueue(int x);
int DeQueue();
private:
int data[QueueSize]; //存放队列的数组
int front,rear; //头指针与尾指针 约定fonrt指向队头元素的前一个元素 ,尾部指针指向队尾元素
};
//从队头插入
void CirQueue::EnQueue(int x)
{
if((rear+1)%QueueSize==front) //判断队列是否已满
cout<<"queue is full,can't put "<<x<<" into it"<<endl;
else
{
//front指向头结点的前一个结点
data[front]=x; //元素x入队
//此时front--才对
front = (front - 1 + QueueSize) % QueueSize;
}
}
//从队尾删除
int CirQueue::DeQueue() //队头元素出栈
{
if(rear == front){ //判断队列是否为空
cout<<"queue is empty"<<endl;
return 0;
}
else
{
int x = data[rear];//保存待删除的值
rear = (rear - 1 + QueueSize) % QueueSize;
return x;
}
}
//测试
int main()
{
CirQueue Q;
Q.EnQueue(1);
Q.EnQueue(2);
Q.EnQueue(3);
cout<<Q.DeQueue()<<endl;
cout<<Q.DeQueue()<<endl;
cout<<Q.DeQueue()<<endl;
Q.DeQueue();
return 0;
}
/*
44、(10)有人设计如下算法用于删除整数顺序表 L 中所有值在[x,y]范围
内的元素,该算法显然不是高效的,请设计一个同样功能的高效算法。( ○ 51 )
void fun(SqList *&L,ElemType x)
{
int i,j;
for (i=0;i<L->length;i++)
if (L->data[i]>=x && L->data[i]<=y)
{
for(j=i;j<L->length-1;j++)
L->data[j]=L->data[j+1];
L->length--;
}
}
*/
#include<iostream>
using namespace std;
const int MaxSize = 100;
struct SqList{
int length;
int data[MaxSize];
};
//原题给的代码
void fun(SqList*& L,int x,int y)
{
int i,j;
for (i=0;i<L->length;i++)
{
if (L->data[i]>=x && L->data[i]<=y)
{
//删除,将后面的值往前移
for(j=i;j<L->length-1;j++)
{
L->data[j]=L->data[j+1];
}
L->length--;
i--;
}
}
}
//优化后的代码
void funSenior(SqList*& L,int x,int y)
{
int i,j,count = 1,jTemp;
for (i=0;i<L->length;i++)
{
if (L->data[i]>=x && L->data[i]<=y)
{
//删除,将后面的值往前移
j = i + 1;
if(j < L->length)
{
L->data[i] = L->data[j];
while(j < L->length && L->data[i]>=x && L->data[i]<=y)
{
count++;//表示减少一次全体平移
j++;
L->data[i] = L->data[j];
}
//剩下的直接全部前移
jTemp = j + 1;
j = i + 1;
while(jTemp < L->length)
{
L->data[j] = L->data[jTemp];
j++;
jTemp++;
}
L->length -= count;
i--;
count = 1;//重置
}
}
}
}
int main()
{
SqList s;
SqList * L = &s;
for(int i = 0;i < 10;i++)
{
L->data[i] = i + 1;
}
L->length = 10;
// fun(L,3,6);
funSenior(L,3,6);
for (int i = 0; i < L->length; i++)
{
cout << L->data[i] << endl;
}
}