王道考研数据结构链表——综合习题题解

Q2Q1:递归删除不带头节点的单链表中所有为x的值

Ans:

void Function(int x,SingleList &L){
	SingleList p = L;
        if(p->next = null||L==null) return;
	if(p->data == x){
		p->next = p->next->next;
	}
	Function(x,p->next);
	
}

Q2:带头节点的单链表删除所有值为x的节点并释放内存

Ans:

void Function(int x,Singlelist &L){
	SingleList p = L,q;
	while(p!= NULL){
		if(p->next->data == x){
			q = p->next;
			p->next = p->next->next;
			free(q);
		}
	}
} 

 Q3:反向输出链表数据

Ans:遍历链表,将数据取出存入数组,数组反向输出


Q4:删除最小节点

Ans:联想删除数组最小值,遍历数组使用min记录最小值下标,一轮遍历结束后再删除最小值。这里使用minp指向最小值的前驱,一轮遍历结束用minp->next = minp->next->next


Q5:单链表原地逆转

Ans:联想顺序表的原地逆转,用一个swap(a,b)完成元素关于中心点交换顺序。这里使用swap函数完成节点关于中心点交换位置。由于限制空间,我们可以牺牲时间来换取空间。


Q6:乱序单链表升序

Ans:用辅助数组取出单链表的数据,排序后再顺序放入单链表内。


Q7:乱序单链表删除所有介于a,b的值。

Ans:循环遍历链表,符合条件删除即可。


Q8:找出两个链表的公共节点。

Ans:如果找寻多个公共节点的话,我觉得得改编一下LCD算法,如果仅仅找一个公共节点的话双重for循环寻找就行。


Q9:乱序单链表升序输出。

Ans:双重循环,内循环寻找最大值输出并删除最大节点然后释放最大节点的内存,外循环控制内循环次数。


Q10:单链表拆分成两个单链表。

Ans:太简单,不说了。


Q11:单链表就地拆分成两个单链表。

Ans:就地拆分要求辅助空间为O(1),a1,b1,a2,b2,a3,b3观察一下发现b1和a3交换可以实现a全部在左边,b全部在右边,变成a1,a3,a2,b2,b1,b3。然后a3,a2交换,b2,b1交换就可以实现a1,a2,a3,b1,b,2,b3然后拆分得到A,B。这题需要先将a交换到左边,b交换到右边,拆分后各自交换内部顺序就可以了。内部交换顺序不能使用递归函数!递归调用系统栈,造成额外的辅助空间!导致辅助空间超过O(1)。


Q12:删除单链表中重复的值。

Ans:没说不能使用set,借用顺序表中去除重复值的方法,将数据取出放入set,使用迭代器遍历放入链表,然后截断链表,释放后面多余节点的内存。


 Q13:将两个升序链表归并为一个降序链表

Ans:使用双重循环将两个升序链表归并为一个升序链表,然后对升序链表做对称变化。


Q15:抽取升序A,B链表公共节点放入A中

Ans:如果没有升序这个条件我觉得需要用到LCD算法,但是说了升序,那就简单多了。

a的指针后移在未找到第一个不小于b指针所指元素前都删除节点,否则如果数值相等将b指针所指节点插入a指针,a,b同时后移一位,如果b>a,则b指针后移一位。这种算法借助了求最长递增子序列的思想,时间复杂度是O(nlog n),比两个链表双重循环从头到尾O(n^2)判断快。

SingleList function(SingleList &a,SingleList b){
		SingleList p = a,q = b;
		while(p != NULL && b != NULL){
			//寻找第一个不小于q->next->data的节点
			//小于直接删除该节点 
			while(p->next->data < b->next->data){ 
				p->next = p->next->next; 
				p = p->next;
			}
			//找到等于的节点将该节点连接上a 
			if(q->next->data = b->next->data;){
				//把b赋给q 
				q = b;
				//q尾插于p 
				q->next = p->next;
				p->next = q;
				//p后移一位 
				p = p->next; 
			}
			//b后移一位 
			b = b->next;
		}
	return a;
} 

Q14:在15的基础上不破坏表a,b

Ans:直接用数组取出a,b的元素,求最长公共子序列就行了。


 Q16:判断b是否为a的连续子序列

Ans:没想到好方法,暴力枚举吧,b中只要有一个元素不和a相同就退出一次外循环。时间复杂度为O(n^2)


Q17:判断带头节点的循环双链表是否对称

Ans:循环双链表是有prior指针的,可以向前搜索也可以向后搜索。所以直接搜索,如果向前和向后同步搜索遇到一个不相同的就不是对称的。如果前行指针p和后行指针q同时指向一个节点或者p->next = q && q->prior = p,搜索结束。


Q18:将两个循环单链表合并为一个循环单链表。

Ans:a表找到表尾,连上b表的头节点,b表找到表尾,连上a表头节点。没什么难度。


Q19:将最小的节点删除直到表空,最后删除头节点。

Ans:这个让我想起了约瑟夫环问题,其实是一样的。包含两个函数地一个是找最小值的前驱,第二个是删除最小值节点。外面套一个循环,最后删除头节点。


Q20:根据访问频度排序,相同频度最近一次访问排在最前。

Ans:让我想起了操作系统的任务调度。索性我不考操作系统,不然又得头疼。1.题目没有说明节点地址是否可以修改,2.没有说明x是否重复。故我设想节点地址可修改,x地址可修改,使用pair<>数组将每个节点的数据和频度取出,将x的频度+1后按照频度进行排序,然后放回链表内。


Q21:输出倒数第K个节点对应的data。

Ans:判断K是否会超过链表长度,如果超过直接返回0,没有超过则将头指针后移并length-k+1位,返回1。

int GetLength(SingleList L){
	int length = 0;
	while(L->link != NULL) length ++;
	return length;
}
int Find_K(SingleList head){
	int length = GetLength(head);
	//链表长度不长于K或空表返回0 
	if(length <= K) return 0;
	//head后移length-K+1位找到倒数第K个节点 
	for(int i = 0 ; i < length-K+1 ; i ++)
	 	head = head->link;
	printf("%d",head->data);
	return 1;
}

 


Q22:找到相同后缀。

Ans:我能想到的最快的办法是以空间换时间,将两个链表的数据分别取出存入数组a,b,a的长度位lenA,b的长度位lenB,a,b逆序寻找第一个不相同的字母位置k,k即为所求位置。然后链表A头指针后移lenA-k+1,链表B头指针后移lenB-k+1,就是链表对应相同后缀的开始节点位置。这种做法写法也比较简单,代码不写了。四个平行单重循环,故时间复杂度位O(n)。


Q23:单链表绝对值去重。

Ans:这类题目貌似在各种抽象数据类型里面都比较吃香,我一直建议使用set容器去重,然后放回链表中。

题目要求给出数据类型定义,下面给出抽象数据类型。

 

class Singlelist{
	private:
		int data;
		SingleList *next;
	public:
		Singlelist Insert();
		Singlelist Pop();
		Singlelist Size();
		Singlelist GetFront();
		Singlelist GetByValue();
		Singlelist Remove(SingleList L);
};

 

你可能感兴趣的:(C++数据结构)