1. 程式人生 > 實用技巧 >兩個有序連結串列的合併1

兩個有序連結串列的合併1

/* ————————————————————————————————*/
// 將兩個有序連結串列升序合併到第三個連結串列//
/* ——————————————————————————————*/
#include <stdio.h>
#include <stdlib.h>

/* 定義結構體 */
typedef struct Node
{
	int data;			 //資料域
	struct Node * pNext; //指標域
}NODE, * PNODE; 
//由於使用了typedef, 所以NODE <=> struct Node  ,  PNODE <=> struct Node * 


/* 函式宣告 */
PNODE create_list();									 //建立一個連結串列
void merge_list(PNODE pHead, PNODE qHead, PNODE rHead);  //將兩個連結串列,升序合併到另一個連結串列 
void traverse_list(PNODE pHead);						 //遍歷整個連結串列並輸出
int main()
{
	//三個連結串列,三個頭指標 
	PNODE pHead = NULL;  //頭指標為空,用來儲存頭結點的地址
	PNODE qHead = NULL;
	PNODE rHead = NULL;
/*————————————————————————————————————————————*/
	//初始化第三個連結串列【只需要分配一個不存放資料的頭結點】 
	//初始化這一步也可以用一個函式來實現 

	PNODE r = (PNODE)malloc(sizeof(NODE));
	if(NULL == r)
	{
		printf("分配失敗,程式終止!");
		exit(-1);
	}
	rHead = r;
	r->pNext = NULL;
/*————————————————————————————————————————————*/	
	pHead = create_list(); //建立一個連結串列,並返回頭結點的地址給pHead
	qHead = create_list(); //建立一個連結串列,並返回頭結點的地址給qHead
	
	printf("\n初始化");
	traverse_list(rHead);  //遍歷整個連結串列
	
	merge_list(pHead, qHead, rHead); 
	
	printf("升序合併後");
	traverse_list(rHead);  //遍歷整個連結串列

	return 0;
}
/* 呼叫函式 */
/*———————————————————————————————————————————————————————*/
PNODE create_list()
{
	int len;      //用來存放有效節點的個數
	int i;
	int temp_val; //臨時存放使用者輸入結點資料域的值

	//分配一個不存放有效資料的頭結點
	PNODE pHead = (PNODE)malloc(sizeof(NODE));

	if(NULL == pHead)
	{
		printf("分配失敗,程式終止!");
		exit(-1);
	}

	PNODE pTemp = pHead; //臨時存放頭結點的地址
	pTemp->pNext = NULL;

	printf("請輸入您要生成的連結串列節點的個數: len = ");
	scanf("%d", &len);

	for(i = 0; i<len; i++)
	{
		printf("請輸入第%d個節點資料域的值 :", i+1);
		scanf("%d", &temp_val);
		
		//迴圈一次分配一個存放有效資料的結點
		PNODE pNew = (PNODE)malloc(sizeof(NODE));
		if(NULL ==pNew)
		{
			printf("分配失敗,程式終止!");
			exit(-1);
		}

		pNew->data = temp_val;
		
		//尾插法 
		pTemp->pNext = pNew;
		pNew->pNext = NULL;  //每分配一個結點,這個結點就是最後一個,所以它的指標域(pNext)為空
		pTemp = pNew;        //保證前一個結點的指標域都指向後一個結點
	}

	return pHead;  //返回頭結點的地址

}
/*———————————————————————————————————————————————————————*/
void merge_list(PNODE pHead, PNODE qHead, PNODE rHead)
{
	PNODE p, q, r;
	
	p = pHead->pNext;  //p指向第一個有效結點 
	q = qHead->pNext;  //q指向第一個有效結點 

	r = rHead;      //r指向rHead所指向的頭結點【第三個連結串列的頭結點】 
	while(NULL != p && NULL != q)
	{		 
    	//將兩個結點的資料進行比較,資料較小的結點接在頭結點後面,
		if(p->data <= q->data)
		{
			r->pNext = p;
			p = p->pNext;
		}
		else
		{
			r->pNext = q;
			q = q->pNext;
		}
		r = r->pNext;  //【重要的一步】移動第三個連結串列的指標 
	}
	//若其中一個連結串列的結點已經全接在新表中則將另一個連結串列的剩餘結點接在新表的後面
	r->pNext = (NULL != p) ? p : q;
//	free(qHead);
//	free(pHead);

	return;
}

/*———————————————————————————————————————————————————————*/
void traverse_list(PNODE pHead)
{
	PNODE p = pHead->pNext;  //頭結點的指標域賦給r,即首結點賦給r 【注意區分頭結點和首結點】

	printf("連結串列的資料為:\n");
	while(NULL != p)
	{
		printf("%d ", p->data);
		p = p->pNext;        //下一個結點賦給r
	}

	printf("\n\n");

	return;
}