1. 程式人生 > >資料結構——找兩個單鏈表的交叉點,並將交叉點在連結串列ls1中所處的位置打印出來

資料結構——找兩個單鏈表的交叉點,並將交叉點在連結串列ls1中所處的位置打印出來

1、程式檔案
I、
在交叉點/src目錄下分別建立main.c、Linklist.c檔案

//main.c

#include <stdio.h>
#include <stdlib.h> //包括rand()、srand()、abs()等函式
#include <time.h>
#include "LinkList.h"

int main()
{
	//連結串列ls1
	List *ls1 = CreateList();
	//連結串列ls2
	List *ls2 = CreateList();
	
	if (NULL == ls1 || NULL ==  ls2)
	{
		printf ("建立失敗\n");
	}
	
	printf ("建立成功!\n");
	
	int i;
	int num;
	
	srand((unsigned int)time(NULL));
	
	//連結串列ls1長度隨機指定(10,20)
	int len1 = rand()%11 + 10 ;
	
	for (i = 0; i < len1; i++)
	{	
		//尾插
		Insert_Last(ls1, rand()%10 + 1);
	}
	
	//連結串列ls2 = 隨機的長度(1,10) + ls1後面擷取的一段
	int len2 = rand()%10 + 1;
	
	for (i = 0; i < len2; i++)
	{
		Insert_Last(ls2, rand()%10 + 1);
	}

	Node *p1 = ls1->head->next;
	//p1隨機指向的結點範圍(15,20)
	for (i = 0; i < rand()%16 + 5; i++)
	{	
		p1 = p1->next;	
	}
	
	Node *p2 = ls2->head->next;
	//p2先指向ls2的尾結點
	while (p2->next)
	{
		p2 = p2->next;
	}
	
	//p1隨機指向的ls1中的那個結點的地址賦給p2,即插到ls2的鏈尾
	//以此構造交叉鏈
	p2->next = p1->next;

	Display(ls1);
	Display(ls2);
	
	//交叉點
	int pos = Find_Intersection(ls1, ls2);
	
	printf ("交叉點在連結串列ls1中的位置為:%d\n", pos);
	
	Destory(ls1);
	Destory(ls2);
	
	return 0;
}
//LinkList.c

#include <stdio.h>
#include "LinkList.h"
#include <stdlib.h>

//建立連結串列
List *CreateList(void)
{
	List *ls = (List*)malloc(sizeof(List)/sizeof(char));
	
	if (NULL == ls)
	{
		return NULL;
	}
	
	ls->head = (Node*)malloc(sizeof(Node)/sizeof(char));
	
	if (NULL == ls->head)
	{
		free(ls);
		return NULL;
	}
	
	ls->head->next = NULL;//空連結串列
	
	return ls;
}


//尾插
BOOL Insert_Last(List *ls, Data data)
{
	if (NULL == ls)
	{
		return ERROR;
	}
	
	Node *node = (Node *)malloc(sizeof(Node)/sizeof(char));
	
	if (NULL == node)
	{
		return ERROR;
	}
	
	node->data = data;
	node->next = NULL;
	
	Node *tmp = ls->head;//頭結點
	
	//作表示式時,取指標變數中存放的地址值
	while (tmp->next)
	{
		tmp = tmp->next;
	}
	
	//tmp->next相當於int *p = &a中的p
	tmp->next = node;
	
	return TRUE;
}

//找交叉點
int Find_Intersection(List *ls1, List *ls2) 
{
	if (ls1 == NULL || ls2 == NULL)
	{
		return -1;
	} 
	
    Node *p1 = ls1->head->next;
    Node *p2 = ls2->head->next;
	
    int len1 = 1;
	int len2 = 1;
	int count = 0;
	
	//分別統計長度
    while (p1->next != NULL) 
	{
        len1++;
        p1 = p1->next;
    }
	
    while (p2->next != NULL) 
	{
        len2++;
        p2 = p2->next;
    }

	p1 = ls1->head->next;
    p2 = ls2->head->next;

	if (len1 >= len2)
	{
		int num = len1 - len2;
		count = num;
		
		while (num > 0) 
		{
			p1 = p1->next;
			num--;
		}
		
		//這裡直接判斷p1 和 p2是否相等,因為較短連結串列的頭結點可能就是交點
		while (p1 != p2) 
		{
			p1 = p1->next;
			p2 = p2->next;
			count++;
		}	
			
		return count+1;
	}
	else
	{
		int num = len2 - len1;
		
		while (num > 0) 
		{
			p2 = p2->next;
			num--;
		}
		
		//這裡直接判斷p1 和 p2是否相等,因為較短連結串列的頭結點可能就是交點
		while (p1 != p2) 
		{
			p1 = p1->next;
			p2 = p2->next;
			count++;
		}	
			
		return count;
	}

}


//列印
void Display(List *ls)
{
	if (NULL == ls)
	{
		return;
	}

	Node *tmp = ls->head->next;//第一個結點
	
	while (tmp)
	{
		printf ("%-4d", tmp->data);
		tmp = tmp->next;
	}
	
	printf("\n");
}

//銷燬	
void Destory(List *ls)
{
	if (NULL == ls)
	{
		return;
	}
	
	Node *tmp = ls->head;
	
	//取0x1000中存放的地址/取首結點的地址、或稱取頭結點中的地址值
	while (tmp->next)
	{
		Node *p = tmp->next;
		tmp->next = p->next;
		free(p);
	}
	
	free(ls->head);
	free(ls);
}	

II、
在交叉點/include目錄下建立Linklist.h檔案

#ifndef _LINKLIST_H_
#define _LINKLIST_H_

typedef enum {TRUE, FALSE, ERROR} BOOL;
typedef int Data; 

//每一個結點中應包含一個指標變數,用它來存放下一結點的地址
typedef struct _node
{
	//資料域
	Data data;
	
	//指標域
	struct _node *next;
}Node;

typedef  struct _list
{
	//頭節點
	Node *head;
}List;

//建立連結串列
List *CreateList(void);

//尾插
BOOL Insert_Last(List *ls, Data data);

//找交叉點
int Find_Intersection(List *ls1, List *ls2);

//列印
void Display(List *ls);

//銷燬
void Destory(List *ls);

#endif //_LINKLIST_H
	

III、
在“交叉點”目錄下建立Makefile檔案

src1 = $(wildcard ./src/*.c) 	
obj1 = $(patsubst ./src/%.c, ./obj/%.o, $(src1))  
	
target = ./bin/a.out
all:$(target)
	
$(target):$(obj1)
	gcc $(^) -o $(@)  

$(obj1):./obj/%.o:./src/%.c	
	gcc -c $(^) -I ./include -o $(@) -g

.PHONY:clean all
clean:
	-rm -rf $(target) $(obj1)	

2、測試結果

[email protected]:/交叉點# ./bin/a.out 
建立成功!
10  6   10  4   6   7   9   6   4   10  2   8   10  8   4   10  3   5   4   
6   4   10  2   8   10  8   4   10  3   5   4   
交叉點在連結串列ls1中的位置為:9