有关单链表的面试题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,"拷贝复杂链表");
}