考研数据结构算法题总结

考研数据结构100天

Day1:在带头结点的单链表L中,删除所有值为X的节点,并释放其空间,假设值为的X节点不唯一,试编写算法以实现上述操作
void Del-X(LinkList &L,int x){
	LNode *p=L->next;
	LNode *pre=L;
	LNode *q;
	while(p!=NULL){
		if(p->data==x){
			q=p;
			p=p->next;
			pre->next=p;
			free(q);
		}else{
			pre=p;
			p=p->next;
		}		
	}
} 
Day2:将两个有序顺序表合并为一个新的有序顺序表
算法思想:将A、B中较小的依次存入C中,若剩余,则依次存入C
bool Merge(Sqlist A,Sqlist B,Sqlist &C){
	if(A.length+B.length>MaxSize){
		return false;
	}
	
	int i=0,j=0,k=0;
	while(i<A.length&&j<B.length){
		if(A.data[i]<B.data[j]){
			C.data[k++]=A.data[i++];
		}else{
			C.data[k++]=B.data[j++];
		}	
	}
	
	while(i<A.length){		//A有剩余 
		C.data[k++]=A.data[i++];
	}
	while(j<B.length){ 		//B有剩余 
		C.data[k++]=B.data[j++];
	}
		
	return true; 
}
Day3:设计一个高效算法,将顺序表L中所有元素逆置,要求空间复杂度O(1)
算法思想1:以中间为对称的元素两两互换
算法思想2:递归
算法思想3:迭代
void Reverse1(Sqlist &L){
	int temp;
	for(int i=0;i<L.length/2;i++){
		temp = L.data[i];
		L.data[i] = L.data[L.length-i-1];
		L.data[L.length-i-1] = temp;
	}
}

void Reverse2(int A[],int low,int high){
	if(low<high){
		swap(A[low],A[high]);
		Reverse2(A,low+1,high-1);
	}
}

void Reverse3(int A[],int low,int high){
	int i=low,j=high;
	while(i<j){
		swap(A[low],A[high]);
		i++;
		j--;
	}
}
Day4:对长度为n的顺序表L,编写一个时间复杂度为O(n),空间复杂度为O(1)的算法,该算法删除线性表中所有值为X的数据元素
算法思想1:用一个k依次后移记录不等于x的元素
算法思想2:扫描顺序表,记录x的个数(k),元素前移k个单位
void delete1(Sqlist &L,int x){
	int k=0;
	for(int i=0;i<L.length;i++){
		if(L.data[i]!=x){
			L.data[k++]=L.data[i]; 
		} 
	}
	L.length=k;
}


void delete2(Sqlist &L,int x){
	int k=0;
	for(int i=0;i<L.length;i++){
		if(L.data[i]==x){
			k++;
		}else{
			L.data[i-k]=L.data[i];
		}
	}
	L.length=L.length-k;
}
Day5:从有序顺序表中删除其值在给定的s到t之间的所有元素,如果s或者t不合理或者顺序表为空,则显示错误消息并退出运行
算法思想:同day4
bool delete(Sqlist &L,int s,int t){
	if(L.length==0||s>=t){
		return false;
	}
	int k=0;
	for(int i=0;i<L.length;i++){
		if(L.data[i]>=s&&L.data[i]<=t){
			k++;
		}else{
			L.data[i-k]=L.data[i];
		}
	}
	L.length=L.length-k;
	return true;
}
Day6:从有序顺序表中删除所有值重复的元素,使表中所有元素值不同
bool delete(Sqlist &L){
	if(L.length==0){
		return false;
	}
	int k=0;
	for(int i=1;i<L.length;i++){
		if(L.data[k]!=L.data[i]){
			L.data[++k]=L.data[i];
		}
	}
	L.length=k+1;
	return true;
}
Day7:将长度为n的数组的前p个数值逆置
算法思想:1.前面p个逆置 2.将后n-p个逆置 3.将整体逆置(三次逆置)
void Reverse(int a[],int left,int right,int k){
	int temp,i,j;
	for(i=left,j=right;i<j&&i<left+k;i++,j--){
		temp=a[i];
		a[i]=a[j];
		a[j]=a[i];
	}
}
void change(int a[],int n,int p){
	Reverse(a,0,p-1,p);
	Reverse(a,p,n-1,n-p);
	Reverse(a,0,n-1,n);
}
Day8:同Day7
Day9:删除带头结点的单链表中值最小的结点(假设最小值结点唯一)
算法思想:用四个指针 minpre、minp指向最小的,pre、p遍历链表
void Delete-min(LinkList &L){
	LNode *pre=L;
	LNode *p=L->next;
	LNode *minpre=L;
	LNode *minp=L->next;
	while(p!=NULL){
		if(p->data<minp->data){
			minp=p;
			minpre=pre;
		}
		pre=p;
		p=p->next;	
	}
	minpre->next=minp->next;
	free(minp);
} 
Day10:头插法建立单链表
算法思想:头插防断链
void CreateListHead(LinkList &L,int a[],int n){
	LNode *s;
	L=(LNode *)malloc(sizeof(LNode));
	L->next=NULL;
	
	for(int i=0;i<n;i++){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=a[i];
		s->next=L->next;
		L->next=s;
	}
} 
Day11:尾插法建立单链表
算法思想:尾插尾指针
void CreateListTail(LinkList &L,int a[],int n){
	LNode *s,*r;
	L=(LNode *)malloc(sizeof(LNode));
	L->next=NULL;
	r=L;

	for(int i=0;i<n;i++){
		s=(LNode *)malloc(sizeof(LNode));
		s->data=a[i];
		r->next=s;
		r=s;
	}
	r->next=NULL;
}
Day12:逆置带头结点的单链表
算法思想1:从头结点断开,然后头插法建立单链表
算法思想2:用pre,p,r依次后移
void Reverse_linkList1(LinkList &L){
	LNode *p=L->next;
	L->next=NULL;
	LNode *r;		//头插防断链 
	
	while(p!=NULL){
		r=p->next;
		p->next=L->next;
		L->next=p;
		p=r;
	}
}
void Reverse_linkList2(LinkList &L){
	LNode *pre=L->next;
	LNode *p=pre->next;
	LNode *r=p->next;
	
	pre->next=NULL;
	while(r!=NULL){
		p->next=pre;
		pre=p;
		p=r;
		r=r->next;
	}
	p->next=pre;		//连接最后两个结点
	L->next=p; 
}
Day13:设在一个带头结点的单链表中所有元素结点的值无序,编写函数删除表中所有介于给定两个值之间的元素
算法思想:遍历链表,删除符合条件的值
void Delete(LinkList &L,int min,int max){
	LNode *pre=L;
	LNode *p=L->next;
	LNode *q;
	
	while(p!=NULL){
		if(p->data>min&&p->data<max){
			q=p;
			p=p->next;
			pre->next=p;
			free(q);
		}else{
			pre=p;
			p=p->next;
		}
	}
}
Day14:给定两个单链表,编写算法找出两个链表的公共结点(Y型)
算法思想1:暴力遍历法
算法思想2:p后移到和q相同的位置,在一起后移
LNode *search_common1(LinkList La,LinkList Lb){
	LNode *p=La->next;
	LNode *q=Lb->next;
	while(p!=NULL){
		while(q!=NULL){
			if(p=q){
				return p;
			}
			q=q->next;
		}
		
		q=Lb->next;		//回到第一个结点 
		p=p->next;	
	}
	return NULL; 
}
LNode *search_common2(LinkList La,LinkList Lb){
	int lenA=getLength(La); 
	int lenB=getLength(Lb); 
	int k;
	LNode *p,*q;
	
	if(lenA-lenB>0){
		k=lenA-lenB;
		p=La->next; 
		q=Lb->next; 	
	}else{
		k=lenB-lenA;
		p=Lb->next; 
		q=La->next; 
	}
	while(k--){
		p=p->next;		//让p后移k位和q对齐 
	}
	
	while(p!=NULL){
		if(p==q){
			return p;
		}
		p=p->next;
		q=q->next;
	} 
	return NULL;
}
Day15:将一个带头结点的单链表A分为两个带头结点的单链表A和B,使得A表中含有表中序号为奇数的元素,B中含有表中序号为偶数的元素,且保持其相对顺序不变
算法思想:不断使用尾插法,依次生成链表A、B
void Divide(LinkList &A,LinkList &B){
	B=(LinkList)malloc(sizeof(LNode));
	B->next=NULL;
	
	LNode *ra=A;
	LNode *rb=B;
	
	LNode *p=A->next;
	A->next=NULL;
	int i=1;

	while(p!=NULL){
		if(i%2==1){
			ra->next=p;
			ra=p;
			p=p->next;
		}else{
			rb->next=p;
			rb=p;
			p=p->next;
		}
		i++;
	}
	ra->next=NULL;
	rb->next=NULL;
}
Day16:设C={a1,b1,a2,b2,a3,b3…an,bn},采用带头结点的C存储,设计一个就地算法,将其拆分为两个单链表,使得A={a1,a2,a3,an},B={bn…b2,b1}
算法思想:遍历C链表,依次将第一个节点尾插A,第二个节点头插B
void Divide(LinkList &A,LinkList &B,LinkList &C){
	A=(LinkList)malloc(sizeof(LNode));
	B=(LinkList)malloc(sizeof(LNode));
	A->next=NULL;
	B->next=NULL;
	LNode *ra=A,*rb;		//B表头插防断链,A表尾插尾指针 
	
	LNode *p=C->next;
	free(C);
	while(p!=NULL){
		ra->next = p;
		ra=p;
		p=p->next;
		if(p!=NULL){
			rb=p->next;
			p->next=B->next;
			B->next=p;
			p=rb;
		}
	}
	ra->next=NULL;
}
Day17:在一个递增有序的单链表中,有数值相同的元素存在,设计算法去掉数值相同的元素
算法思想1:由于单链表递增有序,所以值相同的结点相邻,双指针法
算法思想2:由于单链表递增有序,所以值相同的结点相邻,单(双)指针法
void Del_same1(LinkList &L){
	LNode *pre=L->next;
	LNode *p=pre->next;
	LNode *q;
	
	while(p!=NULL){
		if(pre->data==p->data){
			q=p;
			p=p->next;
			pre->next=p;
			free(q);
		}else{
			pre=p;
			p=p->next;
		}
	} 
} 
void Del_same2(LinkList &L){
	LNode *p=L->next;
	LNode *q;
	while(p!=NULL){
		q=p->next;
		if(q->data==p->data){
			p->next=q->next;
			free(q);
		}else{
			p=p->next;
		}
	}
}

Day18:假设有两个按元素值依次递增次序排列的线性表,均以单链表形式存储,请编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表
算法思想:两个单链表值较小的头插入新链表(逆置)
LinkList Merge(LinkList &A,LinkList &B){
	LNode *p=A->next;
	LNode *q=B->next;
	A->next=NULL;
	free(B);
	LNode *r;		//头插防断链
	 
	while(p!=NULL&&q!=NULL){
		if(p->data<q->data){
			r=p->next;
			p->next=A->next;
			A->next=p;
			p=r;
		}else{
			r=q->next;
			q->next=A->next;
			A->next=q;
			q=r;
		}
	}
	
	while(p!=NULL){		//A有剩余 
		r=p->next;
		p->next=A->next;
		A->next=p;
		p=r;
	}
	while(q!=NULL){		//B有剩余 
		r=q->next;
		q->next=A->next;
		A->next=q;
		q=r;
	}	

	return A;
}
Day19☆☆☆☆☆:设A、B是两个单链表(带头结点),其中元素递增有序,设计一个算法从A和B中的公共元素产生单链表C,要求不破坏A、B的结点
算法思想:A、B有序,依次后移较小的元素结点,直到相等,创造一个新节点存储这个相等的值,尾插法存入C,A、B结点同时后移,重复执行此过程,直到表尾,若A、B表有剩余,不用处理;
LinkList Common(LinkList A,LinkList B){
	LinkList C = (LinkList)malloc(sizeof(LNode));
	C->next = NULL;
	LNode *r=c;
	
	LNode *p=A->next; 
	LNode *q=B->next; 
	LNode *s; 
	
	while(p!=NULL&&q!=NULL){
		if(p->data<q->data){		//寻找相等的结点 
			p=p->next;
		}else if(q->data<p->data){
			q=q->next;
		}else{
			s=(LNode *)malloc(sizeof(LNode));
			s->data=p->data;
			r->next=s;
			r=s;
			p=p->next;
			q=q->next;
		}
	}
	r->next=NULL;
	return C;
}
Day20☆☆☆☆☆:设A、B是两个单链表(带头结点),其中元素递增有序,求A、B交集并存放在A中
算法思想:A、B有序,依次后移较小的元素结点,直到相等,尾插入A链,A、B后移,重复此过程直到表尾(别忘了free结点和A、B剩余部分的结点)
LinkList Common(LinkList &A,LinkList &B){
	LNode *p=A->next; 
	LNode *q=B->next; 
	A->next=NULL;		//用A存储新链表 
	free(B);			//释放B 
	LNode *r=A;			//A的尾指针 
	LNode *u;			//工具指针:释放 
	
	while(p!=NULL&&q!=NULL){
		if(p->data<q->data){
			u=p;
			p=p->next;
			free(u);
		}else if(q->data<q->data){
			u=q;
			p=q->next;
			free(u);
		}else{
			r->next=p;
			r=p;
			p=p->next;
			u=q;
			q=q->next;
			free(u);
		}
	}
	r->next=NULL;
	
	while(p!=NULL){		//释放p剩下的 
		u=p;
		p=p->next;
		free(u);
	}
	while(q!=NULL){		//释放q剩下的 
		u=q;
		q=q->next;
		free(u);
	}	
	
	return A; 
}
Day21:两个整数数列A=a1,a2,a3…am和B=b1,b2,b3…,bn已经存入两个单链表中,设计一个算法,试判断序列B是否是A的连续子序列
算法思想:依次遍历A、B,比较p->data与q->data,若相等,一起后移,若不等,A从上次结点开始比较结点的后继开始,B从头开始
bool son(LinkList A,LinkList B){
	LNode *p=A->next;
	LNode *q=B->next;
	LNode *pre=A->next;
	while(p!=NULL){
		while(q!=NULL){
			if(p->data!=q->data){
				break;
			}
			q=q->next;
			p=p->next;
		}
		if(q==NULL){
			return true;
		}	
		pre=pre->next;
		p=pre;
		q=B->next;
	}
	return false;
}
Day22:设计一个算法判断带头结点的循环双链表是否对称
算法思想:让p从左往右扫描,q从右往左扫描,直到指向痛殴一个结点(偶数)或相邻(奇数),则他们是对称的,返回1,否则返回0
int symmentry(DLinkList L){
	DLNode *p=L->next;
	DLNode *q=L->prior;
	
	while(p!=q&&q->next!=p){
		if(p->data==q->data){
			p=p->next;
			q=q->prior;
		}else{
			return 0;
		} 
	}
	return 1;
}
Day23:有两个循环无头结点单链表,链表头指针分别是h1和h2,编写一个函数将链表h1链接到链表h2之后,要求链接后的链表仍保持循环链表的形式
算法思想:找到两个单链表的尾指针,相连
void link(LNode *&h1,LNode *&h2){
	LNode *p=h1;
	LNode *p=h2;
	
	while(p->next!=NULL){
		p=p->next;
	}
	while(q->next!=NULL){
		q=q->next;
	}
	
	p->next=h2;
	q->next=h1;
}
Day24:设有一个带头结点的循环单链表,起结点值均为正整数,设计一个算法,反复找出单链表中结点值最小的结点输出,然后将结点从中删除,直到单链表空为止,再删除表头结点
算法思想:循环找最小删除
void DelAllMin(LinkList &L){
	LNode *pre,p,minpre,minp;
	
	while(L->next!=NULL){
		pre=L;
		p=L->next;
		minpre=L;
		minp=L->next;
		
		while(p!=NULL){
			if(p->data<minp->data){
				minpre=pre;
				minp=p;
			}
			pre=p;
			p=p->next;
		}
		
		printf("%d",minp->data);
		minpre->next=minp->next;
		free(minp); 
	}
	
	free(L);
}
Day25:设头指针为L的带有表头结点的非循环双链表,其每个结点中除有prior指针域、data数据域和next指针域外,还有一个访问频度freq。在链表被启用前,其值均初始化为零,每当在链表中进行一次Locate(L,x)运算时,令元素为x的结点中freq加1,并使此链表中结点保持按访问频度递减的顺序排列,同时,最近访问的节点排在频度相同的结点前面,以便使频繁访问的结点总是靠近表头,编写符合上述要求的Locate(L,x)运算的算法,该运算为函数过程,返回找到结点的地址,类型为指针型
算法思想:找到含x的结点,使freq加1,取下该结点,根据freq的大小插入到第一个比他大的后面
	DLNode *p=L->next;
	DLNode *q;
	while(p&&p->data!=x){		//p不空或者不等于x后移 
		p=p->next;
	}
	if(p==NULL){
		return NULL;
	}	
	
	q=p->prior;
	p->freq++;
	if(p->next!=NULL){		//取下p 
		p->next-prior=p->prior;
		p->prior->next=p->next;
	}else{
		p->prior->next=NULL;
	}
	
	while(q!=L&&q->freg<=p->freg){
		q=q->prior;		//找到合适的插入位置 
	} 
	p->next=q->next;
	p->prior=q;
	q->next=p;
	p->next->prior=p;
	
	return p;
	
} 
Day26:已知一个带头结点的单链表,请设计一个算法,查找该链表倒数第k(正整数)个位置上的结点,若查找成功,算法输出该节点data域的值,并返回1,否则返回0
算法思想:用两个相差k个结点的指针pq依次后移,q为空则p为倒数第k个
int searchK(LinkList L,int k){
	LNode *p=L->next;
	LNode *q=L->next;
	while(k--&&q!=NULL){
		q=q->next;		//p、q相差k 
	}
	if(k!=0){
		reutrn 0;
	}
	
	while(q!=NULL){
		q=q->next;
		p=p->next;
	}
	prinf("%d",p->data);
	return 1;
}
Day27:假定采用带头结点的单链表保存两个单词有相同的后缀时,可享受相同的后缀存储空间,例如loading和being共用ing,设计算法找出两个链表共同后缀的起始位置
算法思想:求出str1和str2的长度,将较长的移动k(长度差),反复后移p,q直到指向同一地址(代码同day14)

-

Day28:用单链表保存m个整数,且data的绝对值小于等于n(正整数),现要求设计一个时间复杂度尽可能高效的算法,对于链表中data绝对值相等的结点,仅保存第一次出现的结点而删除其绝对值相等的结点。
算法思想:以空间换时间,申请一个大小n+1的辅助空间(初始化为0),第一次出现保留(0变1),否则删除结点
void deleteSame(LinkList &L,int n) {
	LNode *pre=L;
	LNode *p=L->next;
	int *c=(int *)malloc(sizeof(int)*(n+1));
	for(int i=0;i<n+1;i++){
		c[i]=0;
	}
	int m;
	
	while(p!=NULL){
		m=p->data>0?p->data:-(p->data);
		if(c[m]=0){
			c[m]=1;
			pre=p;
			p=p->next;
		}else{
			pre->next=p->next;
			free(p);
			p=pre->next;
		}
	}
	free(c);
}
Day29:设线性表L=(a1,a2,a3…,an-1,an-1,an)采用带头结点的单链表保存,设计一个尽可能高效的算法,重新排列L中的各结点,得到线性表L1=(a1,an,a2,an-1,a3,an-2…)
算法思想:①找中间②逆置后半个链表③后半个链表插入到合适的位置
void change_list(LinkList &L){
	LNode *p,*q,*r,*s;
	p=q=L;
	while(q->next!=NULL){		//第一步,找中间 
		p=p->next;				//走一步 
		q=q->next;				//走两步 
		if(q->next!=NULL){
			q=q->next;
		}
	}	
	q=p->next;		//p为中间结点,q指向后半段链表首结点 
	p->next=NULL;		//断开 
	
	while(q!=NULL){		//逆置后半段 
		r=q->next;
		q->next=p->next;
		p->next=q;
		q=r;
	} 
	
	s=L->next;		//合并,s指向前半段的第一个数据结点 
	q=p->next;
	while(q!=NULL){		//将后半段结点插入合适的位置 
		r=q->next;
		q->next=s->next;
		s->next=q;
		s=q->next;
		q=r;	
	} 
}
Day30总结:
①头插法防断链
②尾插法尾指针
③逆置(顺序表和单链表)
④归并法(分解)
⑤双指针法(取较小,倒数第k个元素,中间元素)
⑥循环双链表(插入和删除)
  • 22
    点赞
  • 231
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值