算法设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.试编写在带头结点的单链表中删除(一个)最小值结点的(高效)算法。
【题目分析】本题要求在单链表中删除最小值结点。
单链表中删除结点,为使结点删除后不出现“断链”,应知道被删结点的前驱。
而“最小值结点”是在遍历整个链表后才能知道。
所以算法应首先遍历链表,求得最小值结点及其前驱。
遍历结束后再执行删除操作。
LinkedList Delete(LinkedList L)
∥L是带头结点的单链表,本算法删除其最小值结点。
{p=L->next;∥p为工作指针。
指向待处理的结点。
假定链表非空。
pre=L;∥pre指向最小值结点的前驱。
q=p;∥q指向最小值结点,初始假定第一元素结点是最小值结点。
while(p->next!=null)
{if(p->next->data<q->data){pre=p;q=p->next;} ∥查最小值结点
p=p->next;∥指针后移。
}
pre->next=q->next;∥从链表上删除最小值结点
free(q);∥释放最小值结点空间
}∥结束算法delete。
2.将两个递增的有序链表合并为一个递增的有序链表。
要求结果链表仍使用原来两个链表的存储空间, 不另外占用其它的存储空间。
表中不允许有重复的数据。
void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc){
pa=La->next; pb=Lb->next;
Lc=pc=La; //用La的头结点作为Lc的头结点
while(pa && pb){
if(pa->data<pb->data){ pc->next=pa;pc=pa;pa=pa->next;}
else if(pa->data>pb->data) {pc->next=pb; pc=pb; pb=pb->next;}
else {// 相等时取La的元素,删除Lb的元素
pc->next=pa;pc=pa;pa=pa->next;
q=pb->next;delete pb ;pb =q;}
}
pc->next=pa?pa:pb; //插入剩余段
delete Lb; //释放Lb的头结点}
3.已知长度为n的线性表A采用顺序存储结构,请写一时间复杂度为O(n)、空间复杂度为O(1)的算法,该算法删除线性表中所有值为item的数据元素。
【题目分析】在顺序存储的线性表上删除元素,通常要涉及到一系列元素的移动(删第i个元素,第i+1至第n个元素要依次前移)。
本题要求删除线性表中所有值为item的数据元素,并未要求元素间的相对位置不变。
因此可以考虑设头尾两个指针(i=1,j=n),从两端向中间移动,凡遇到值item的数据元素时,直接将右端元素左移至值为item的数据元素位置。
void Delete(ElemType A[ ],int n)
∥A是有n个元素的一维数组,本算法删除A中所有值为item的元素。
{i=1;j=n;∥设置数组低、高端指针(下标)。
while(i<j)
{while(i<j && A[i]!=item)i++;∥若值不为item,左移指针。
if(i<j)while(i<j && A[j]==item)j--;∥若右端元素值为item,指针左移
if(i<j)A[i++]=A[j--];
}
4.已知一个带有表头结点的单链表,结点结构为:
假设该链表只给出了头指针list
查找链表中倒数第K位置的结点(K为正整数),若查找成功,算法输出该结点 data域的值,
并返回1,否则只返回0;要求:
(1)简述算法的基本设计思想;
(2)描述算法的详细实现步骤(使用C,或C++实现),关键之处给出详细解释。
int LocateElement(linklist list,int k)
{
P1=list->link; P=list; i=1; while(P1) {
P1=P1->link; i++;
if(i>k) P=P->next; //如果i>k,则p也往后移 }
if(P==list) return 0; //说明链表没有k个结点
else {
printf(“%d\n“,P->data);
return 1; }
}
5. 已知非空线性链表第一个结点的指针为list,请写一个算法,将该链表中数据域值最大的那个结点移到链表的最后面。
void REMOVE(LinkList & list){
LinkList s,r,p,q;
q=list;
p=list->link;
r=list;
While(p!=NULL)
{ if(p->data->q->data) then
{ s=r; q=p; }
r=p;p=p->link;}
if(q!=r) then
{ if (q==list) then list=q->link;
else
s->link=q->link; r->link=q; q->link=NULL;
} }
6.若已知非空线性链表第一个结点的指针为list,请写一个算法,将该链表中数据域值最小的那个结点移到链表的最前端。
void REMOVE(LinkList & list){
LinkList q=list, s ,r;
p=list->link ;
While(p!=NULL)
{
if(p->data->q->data) then
{ s=r; q=p; }
r=p;p=p->link;
}
if(q!=list) then
s->link=q->link; q->link=list;
list=q; }
}
7.已知一个带有表头结点的单链表,头指针为L,请用一个尽可能高效的算法实现,在非头结点p所指元素前,插入元素e,并分析算法的时间复杂度。
时间复杂度O(n)
Delete(Node *L, Node *p)
{ Node *s, *t s = L->next; t = L;
while (s != NULL && s != p){
t = s; s = s->next; }
if (s != NULL){ t->next = s->next; free(s);} }
9.试设计实现在单链表中删去值相同的多余结点的算法。
typedef int datatype;
typedef struct node {datatype data; struct node *next;}lklist;
void delredundant(lklist *&head)
{ lklist *p,*q,*s;
for(p=head;p!=0;p=p->next)
{ for(q=p->next,s=q;q!=0; )
if (q->data==p->data) {s->next=q->next; free(q);q=s->next;}
else {s=q,q=q->next;}
}
}
10.编写算法,判断带头结点的双向循环链表L是否对称。
对称是指:设各元素值a1,a2,...,a n, 则有a i=a n-i+1 ,即指:a1= a n,a2= a n-1 。
结点结构为:
int judge(DLinkList L) {
p=L->next; q=L->prior;
while(p!=q) {
if(p->data!=q->data)
return 0;
if(p->next==q)
return 1;
p=p->next; q=q->prior; }
return 1; }
11.已知带头结点的动态单链表L中的结点是按整数值递增排列,试写一算法将值为X的结点插入链表L中,使L仍然有序。
分析:本题算法的思想是先建立一个待插入的结点,然后依次与链表中的各结点的数据域比较大小,找到插入该结点的位置,最后插入该结点。
实现本题功能的函数如下:
void insertorder(Linklist &L, Elemtype x) { Linklist p,q,s;
s=(Linklist)malloc(sizeof(Lnode));
s->data=x; s->next=NULL; //产生一个待插入的结点s
q=L;
p=q->next;
while( p && x>p->data)
{ q=p; /使q始终指向p的前驱
p=p->next; }
s->next=p; q->next=s; //将s结点插入到q和p之间
}
12.假设线性表采用顺序存储结构,编写算法,将顺序表L 中所有值为奇数的元素调整到表的前端。
viod f34 (Seqlist head)
{ int temp,m=0;
for(i=0;i<t->length;i++)
{
if(p->data[i] mod 2 !=0)
{
temp=t->data[m]; t->data[m]= t->data[j];
t->data[i]=temp m++; } } }
20.已知一个整数序列A= (a0, a1,…,a n-1) ,其中0≤a i< n(0 ≤ i< n) 。
若存在a p=a p2 =…=a pm=x且m >n/2(0 ≤p k<n,1≤k≤m),则称x 为A 的主元素。
例如A=( 0, 5,5,3,5,7,5,5 ),则5 为主元素;又如A= ( 0,5,5,3,5,1,5,7 ),则A 中没有主元
素。
假设A 中的n 个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出A 的主元素。
若存在主元素,则输出该元素;否则输出-1。
要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,采用C 或C++或Java 语言描述算法,关键之处给出注释。
(3)说明你所设计算法的时间复杂度和空间复杂度。
(1)算法的策略是从前向后扫描数组元素,标记出一个可能成为主元素的Num 。
然后重新计数,确认 NumNum 是否主元素。
算法可分为以下两步:①选取候的主元素:依次扫描所给数组中的每个整,将第一遇到Nu m保存到 c中,记录 Nu m的出现次数为的出现次数为 1;若遇到的下一个整数仍等于 NumNum ,则计数加 1,否则计数减 1;当计数减到 0时,将遇到的下一个整数保存c中,计数重新记为中,计数重新记为 1,开始新一轮计数,即从当前位置重复上述过程直到扫描完全部组元素。
②判断 c中元素是否真正的主中元素是否真正的主:再次扫描该数组,统计 c中元素出现的次数,若中元素出现的次数,若大于 n/2 ,则为主元素;否则,序列中不存在主元素。
(2)算法实现:(7分)
int Majority(int A[], int n)
{int i, c, count=1; / / c用来保存候选主元素,count用来计数
c = A[0]; / / 设置A[0]为候选主元素
for ( i=1; i<n; i++ ) / / 查找候选主元素
if ( A[i] = = c ) count++; / / 对A中的候选主元素计数
else if ( count > 0) / / 处理不是候选主元素的情况
count--;else / / 更换候选主元素,重新计数
{ c = A[i];count = 1;}
if ( count>0 ) for (i=count=0; i<n; i++ )/ / 统计候选主元素的实际出现次数
if ( A[i] = = c ) count++;
if ( count> n/2 ) return c; / / 确认候选主元素
else return -1; / / 不存在主元素
}
1.统计一棵二叉树的叶子结点的个数
// 求二叉树中叶子结点的数目
Status POLeafNodeNum(int& i,BiTree& T)
{ if(T) {
if(!T->lchild && !T->rchild) i++;
POLeafNodeNum(i,T->lchild); POLeafNodeNum(i,T->rchild);}
return OK;}
2.统计一棵二叉树的度为2的结点个数
int Degrees2(BinTreeNode *t) {
if (!t) return 0;
if(t->leftChild && t->rightChild)
return 1+Degrees2(t->leftChild)+Degrees2(t->rightChild);
}
3.统计一棵二叉树的深度
int Height(btre bt)//求二叉树bt 的深度
{int hl,hr;
if (bt==null) return(0);
else {hl=Height(bt->lch); hr=Height(bt->rch);
if(hl>hr) return (hl+1); else return(hr+1);
} }
4.创建一棵二叉树
BiTree Creat() //建立二叉树的二叉链表形式的存储结构
{ElemType x;BiTree bt;
scanf(“%d”,&x); //本题假定结点数据域为整型
if(x==0) bt=null;
else if(x>0)
{bt=(BiNode *)malloc(sizeof(BiNode));
bt->data=x; bt->lchild=creat(); bt->rchild=creat();
}
else error(“输入错误”);
return(bt);
}//结束 BiTree
7.以二叉链表作为二叉树的存储结构,计算二叉树最大的宽度(二叉树的最大宽度是指二叉树所有层中结点个数的最大值)。
[题目分析] 求二叉树高度的算法见上题。
求最大宽度可采用层次遍历的方法,记下各层结点数,每层遍历完毕,若结点数大于原先最大宽度,则修改最大宽度。
int Width(BiTree bt)//求二叉树bt的最大宽度
{if (bt==null) return (0); //空二叉树宽度为0
else
{BiTree Q[];//Q是队列,元素为二叉树结点指针,容量足够大
front=1;rear=1;last=1;//front队头指针,rear队尾指针,last同层最右结点在队列中的位置
temp=0; maxw=0; //temp记局部宽度, maxw记最大宽度
Q[rear]=bt; //根结点入队列
while(front<=last)
{p=Q[front++]; temp++; //同层元素数加1
if (p->lchild!=null) Q[++rear]=p->lchild; //左子女入队if (p->rchild!=null) Q[++rear]=p->rchild; //右子女入队
if (front>last) //一层结束,
{last=rear;
if(temp>maxw) maxw=temp;//last指向下层最右元素, 更新当前最大宽度
temp=0;
}//if
}//while
return (maxw);
}//结束width
1.设二叉排序树bt以二叉链表为存储结构,试设计算法删除二叉排序树bt中值最大的结点。
Status del_max(BiTree &bt){ --------1分 //删除二叉排序树bt中值最大结点
if (!bt) return ERROR; //空树
p = bt;
if (bt->rchild == NULL){ //根无右子树 --------2分
bt = bt->lchild; p->lchild = NULL;//此语句可不要
free(p); }
else{ while(p->rchild != NULL){//p移至最右下结点
q = p; p = p->rchild;}
if(p->lchild != NULL)//有左子树 --------5分
q->rchild = p->lchild;
else q->rchild = NULL;//无左子树
free(p); } }//del_max
1.试写出将S结点插入到双向链表P结点之前的语句序列,结点结构为:
S->priou=P->priou;
P->priou=S;
S->next=P;
P->priou->next=S;。