链表面试题2

有关单链表的面试题2


复杂链表的复制

//复杂链表的复制
typedef struct ComplexNode{
	LinkNodeType data;
	struct ComplexNode* next;
	struct ComplexNode* random;
}ComplexNode;

ComplexNode* CreateComplexNode(LinkNodeType value){
	ComplexNode* new_node = (ComplexNode*)malloc(sizeof(ComplexNode));
	new_node->data = value;
	new_node->next = NULL;
	new_node->random = NULL;
	return new_node;
}

size_t Diff(ComplexNode* src , ComplexNode* dest){
	size_t offset = 0;
	while(src != NULL){
		if(src == dest){
			break;
		}
		++offset;
		src=src->next;
	}
	if(src==NULL){
		return (size_t)-1;
	}
	return offset;
}
ComplexNode* Step(ComplexNode* head ,size_t offset){
	ComplexNode* cur = head;
	size_t i = 0;

	while(1){
		if(cur == NULL){
			return NULL;
		}
		if(i>=offset){
			return cur;
		}
		++i;
		cur = cur->next;
	}
	return NULL;
}

ComplexNode* CopyComplexList(ComplexNode* head){
	if(head == NULL) {
		return NULL;
	}
	//先按照简单链表来进行复制
	ComplexNode* new_head = NULL;
	ComplexNode* new_tail = NULL;
	ComplexNode* cur = head;
	for(;cur != NULL;cur = cur->next){
		ComplexNode* new_node = CreateComplexNode(cur->data);
		if(new_head == NULL){
			new_head = new_tail = cur;
		}else {
			new_tail->next = new_node;
			new_tail = new_tail->next;
		}
	}
	//遍历旧链表,找到每个链表节点random指针相对与链表头部的偏移量
	//遍历新链表,根据偏移量,设置新链表的random
	ComplexNode* new_cur = new_head;
	for(cur = head;cur!=NULL;cur=cur->next,new_cur=new_cur->next){
		if(cur->random == NULL){
			new_cur->random = NULL;
			continue;
		}
		//通过Diff函数来计算两个节点的偏移量
		size_t offset = Diff(head ,cur->random);
		//通过Step函数,相当与求出从new_head出发,走了offset步,到达的位置是谁
		new_cur->random = Step(new_head,offset);
	}
	return new_head;
}


两个有序链表求交集


LinkNode* LinkListUnionSet(LinkNode* head1 , LinkNode* head2) {
	if(head1 == NULL || head2 == NULL) {
		return NULL;
	}
	LinkNode* cur1 = head1;
	LinkNode* cur2 = head2;
	LinkNode* new_head = NULL;
	LinkNode* new_tail = NULL;
	while(cur1 != NULL && cur2 != NULL) {
		if(cur1->data < cur2->data){
			cur1 = cur1->next;
		}else if(cur1->data > cur2->data) {
			cur2 = cur2->next;
		}else {
			//两个相等
			if(new_head == NULL){
				new_head = new_tail = CreateNode(cur1->data);
			}else{
				new_tail->next = CreateNode(cur1->data);
				new_tail = new_tail->next;
			}
			cur1 = cur1->next;
			cur2 = cur2->next;
		}
	}
	return new_head;
}
判断两个单链表是否相交(可能带环)

int LinkListHasCrossWithCycle(LinkNode* head1 , LinkNode* head2) {
	if(head1 == NULL && head2 == NULL) {
		//空链表
		return 0;
	}
	//求连个链表的入口点
	LinkNode* entry1 = LinkListCycleEntry(head1);
	LinkNode* entry2 = LinkListCycleEntry(head2);
	//如果两个链表都不带环,则按照前面的方法判定
	if(entry1 == NULL && entry2 == NULL) {
		return LinkListHasCross1(head1 , head2);
	}
	//如果一个带环一个不带环,则不相交
	if((entry1 == NULL && entry2 != NULL)||(entry1 != NULL && entry2 == NULL)) {
		return 0;
	}
	//如果两个链表都带环
	//a)如果连个入口相同,说明相交,并且是环外相交
	if(entry1 == entry2) {
		return 1;
	}
	//b)如果从一个入口点出发,绕环一周,能到达第二个入口点说明也是相交,并且是环上相交
	LinkNode* cur = entry1->next;
	while(cur != entry1) {
		if(cur == entry2) {
			return 1;
		}
		cur = cur->next;
	}
	return 0;
}

求可能带环的两个链表相交的交点

LinkNode* LinkListHasCrossWithCyclePos(LinkNode* head1 , LinkNode* head2) {
	if(head1 == NULL && head2 == NULL) {
		return NULL;
	}
	//交点在环外
	LinkNode* entry1 = LinkListCycleEntry(head1);
	LinkNode* entry2 = LinkListCycleEntry(head2);
	if(entry1 == entry2) {
		LinkNode* cur1 = head1;
		LinkNode* cur2 = head2;
		size_t len1 = 0;
		size_t len2 = 0;
		for(cur1 = head1;cur1 != entry1;cur1 = cur1->next){
			len1++;
		}
		for(cur2 = head2 ;cur2 != entry2;cur2 = cur2->next){
			len2++;
		}
		if(len1 > len2) {
			int i = 0;
			for(i=0;i<len1-len2;i++){
				cur1 = cur1->next;
			}
			while(cur1 != NULL && cur2 != NULL) {
				if(cur1 == cur2) {
					return cur1;
				}
				cur1 = cur1->next;
				cur2 = cur2->next;
			}
		}else {
			int i = 0;
			for(i=0;i<len2-len1;i++){
				cur2 = cur2->next;
			}
			while(cur1 != NULL && cur2 != NULL){
				if(cur1 == cur2) {
					return cur1;
				}
				cur1 = cur1->next;
			
				cur2 = cur2->next;
			}
		}
	}
	//环上相交
	if(entry1 != entry2){
	 	LinkNode* cur = entry1;
		for(;cur != entry2;cur = cur->next);
			return cur; 
	}
}

测试代码:

void TestHasCrossWithCyle(){
	//两个链表都不带环
	TEST_HEADER;
	LinkNode* head1;
	LinkListInit(&head1);

	LinkListPushBack(&head1 , 'a');
	LinkListPushBack(&head1 , 'b');
	LinkListPushBack(&head1 , 'c');
	LinkListPushBack(&head1 , 'd');
	LinkListPushBack(&head1 , 'e');

	LinkNode* head2;
	LinkListInit(&head2);
	LinkListPushBack(&head1 , 'a');
	LinkListPushBack(&head1 , 'b');
	LinkListPushBack(&head1 , 'c');

	LinkNode* pos_c = LinkListFind(head2,'c');
	pos_c->next = head1->next;
	int ret1 = LinkListHasCrossWithCycle(head1 ,head2);
	printf("ret1 expected 1,actual %d\n",ret1);
	

}

void TestUnionSet(){
	TEST_HEADER;
	LinkNode* head1;
	LinkListInit(&head1);

	LinkListPushBack(&head1 , 'a');
	LinkListPushBack(&head1 , 'b');
	LinkListPushBack(&head1 , 'c');
	LinkListPushBack(&head1 , 'd');
	LinkListPushBack(&head1 , 'e');

	LinkNode* head2;
	LinkListInit(&head2);
	LinkListPushBack(&head2 , 'a');
	LinkListPushBack(&head2 , 'b');
	LinkListPushBack(&head2 , 'c');
	
	LinkNode* head = LinkListUnionSet(head1 ,head2);
	LinkListPrintChar(head,"两个已排序链表中相同的数");
}

void PrintComplexList(ComplexNode* head ,const char* msg){
	printf("[%s]\n",msg);
	ComplexNode* cur = head;
	for(;cur!=NULL;cur=cur->next){
		printf("[%c] ",cur->data);
	}
	printf("\n");
	for(cur=head;cur!=NULL;cur=cur->next){
		if(cur->random ==NULL){
			printf("[NULL]");
			continue;
		}
		printf("[%c] ",cur->random->data);
	}
	printf("\n");
}
void TestComplexListCopy(){
	TEST_HEADER;
	LinkNode* head;
	LinkListInit(&head);

	ComplexNode* a = CreateComplexNode('a');
	ComplexNode* b = CreateComplexNode('b');
	ComplexNode* c = CreateComplexNode('c');
	ComplexNode* d = CreateComplexNode('d');
	a->next = b;
	b->next = c;
	c->next = d;
	d->next = NULL;
	a->random = c;
	b->random = a;
	c->random = NULL;
	d->random = d;

	ComplexNode* new_head = CopyComplexList(a);
	PrintComplexList(new_head,"拷贝复杂链表");
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值