C語言合併兩個帶頭節點公升序排列鍊錶

2021-07-31 17:22:13 字數 4521 閱讀 4436

合併鍊錶,顧名思義,就是將兩個按順序存放資料的鍊錶中的資料合併為用乙個鍊錶儲存,比如在處理多項式的加減法時就需要將兩個多項式的資料進行合併。合併方式有很多種:如果按照儲存方式的不同,可以將兩個鍊錶的資料分別提取出來生成乙個新的鍊錶來儲存原先兩個鍊錶的資料,還可以將其中乙個鍊錶的資料依次插入到另外乙個鍊錶的相應位置當中去。在遇到相同資料時可以採取只留下乙個資料的方式和兩個資料均保留的方式。這些不同點需要到具體的問題中具體分析,但是只是在細節上有一些差別,大體的思路都是一樣的,本文主要介紹將乙個鍊錶插入到另乙個鍊錶的相應位置,插入完成後銷毀鍊錶二,且遇到相同資料採用均保留的方式。

我們還是先拋開鍊錶的操作本身,先對兩組不同的資料進行合併操作,知道兩組按公升序排列的資料該如何合併成一組資料,我們來分析這樣幾組資料(將第二組的資料插入到第一組中):

1   5   9   13   15

2   7   12

對於這組資料我們可以很輕易的說出應該把「2」插入到「1」的前面,應該把「7」插入到「5」的前面... ... 那麼我們又是如何得到這個結論的呢,接下來我們來用語言細緻的描述一下我們剛才是如何得到這樣的結論的:「首先,遍歷第一組資料,找到第乙個比要插入的資料大的資料的前乙個資料「i」,再將要插入的資料插入到「i」的後面」。

上述描述解決了插入資料的一般性情況,包括我們用「比該資料大」這樣的話說明了遇到相同資料時該如何處理,但是,問題依然存在,我們來觀察下面一組資料:

2   4   7   9

1   3   6   8

我們要將第二組資料插入到第一組資料中,按照之前的說法,找到第乙個不比待插入資料小的資料的前乙個資料「i」,但是我們發現第一組資料中第乙個資料就符合我們的要求,那麼它自然沒有前乙個資料。這裡我們給出乙個方案:在進行插入工作前,先對兩個鍊錶的首元素進行比較,如果鍊錶一的首元素是小於第二個鍊錶的首元素的,那麼開始合併工作,如果鍊錶一的首元素不小於第二個鍊錶的首元素,我們先交換兩個鍊錶的頭結點,使得鍊錶一變成鍊錶二。但是這種方式僅適用於我們當前的情況,因為我們要實現的是將鍊錶二的元素加入到鍊錶一中,之後銷毀鍊錶二,這就意味著我們最後只要得到乙個鍊錶就可以,只要使得傳遞過來的鍊錶一在執行完我們的合併鍊錶程式後能夠變成合併後的結果鍊錶就好了,因此我們可能要更改傳遞過來的鍊錶的頭結點的值。

根據上面的說法,我們就要在開始進行合併之前先對兩個鍊錶的首元素進行比較,如果鍊錶二的首元素比煉表一的首元素大,則交換兩個鍊錶的控制頭,再執行後續的合併工作。

解決了上述問題,還差最後一種情況,我們來觀察下面一組資料:

1   3   4   6   7

2   6   9   10  13

我們可以觀察到,將第二組資料依次向第一組資料中插入,到了「9」的時候,第一組資料就沒有可以插入的位置了,而應該在尾部追加,於是,我們就不能執行之前的操作了,而應該執行另外一項操作,我們具體實現是這樣的:

如果我們在第一組資料中找不到比待插入資料大的資料,我們就將待插入資料的後面的資料連同待插入資料本身,追加到第一組資料的末尾。

根據如上分析,我們需要執行的有四種對鍊錶的操作:1、在指定鏈中找到第乙個比目標資料的大的節點的前驅節點; 2、將指定元素插入到指定鍊錶的指定位置; 3、將鍊錶中的制定位置後的所有元素追加到指定鍊錶的末尾; 4、交換兩個鍊錶的頭結點。

下面我們就分布解決這四種操作(注:a_line是我們自己定義的為了方便起見的乙個結構體,只有乙個int型別的num和乙個a_line *型別的next成員不具有任何意義,僅僅是為了完成合併鍊錶):

1、在指定鏈中找到第乙個比目標資料的大的節點的前驅節點:

a_line *getfirstlocalbiggerthanele(a_line head, a_line ele) 

return q;

}

我們用a_line *p來遍歷鍊錶一,用a_line *q來實時儲存當前節點的前驅節點,鍊錶沒有遍歷完而且當前元素依然小於等於目標元素,則迴圈繼續。當迴圈結束後,判斷迴圈結束的原因,如果是因為鍊錶遍歷完了而結束的迴圈,則說明整個煉表裡都沒有比目標節點大的節點,返回not_found;若是因為找到了比目標元素大的元素而結束的,那麼返回該元素的前驅節點的位址「q」。

2、將指定元素插入到指定鍊錶的指定位置:

void inserteletoline(a_line *local, a_line ele)3、將一段資料追加到指定鍊錶的末尾:

a_line *tarp;

for (tarp = targetline.next; tarp->next != null; tarp = tarp->next)

; tarp->next = line;

}

這裡給出的a_line *line代表著待插入鍊錶的首元素的首位址,targetline代表要插入到的鍊錶的頭結點。首先先定位目標鍊錶的末節點的首位址,再將待插入鍊錶的末節點的next成員更改為待插入鍊錶的首元素的首位址。

但這裡存在著問題,這裡的賦值相當於直接把鍊錶二的一部分節點直接放到鍊錶一的末尾,並不是複製出來乙份再追加到鍊錶一的末尾,這樣就使得鍊錶二的那一部分節點又屬於鍊錶一又屬於鍊錶二,而鍊錶二在最後是要被釋放的,那麼它的後幾個節點也會被釋放。為了防止這樣的情況發生,我們必須將鍊錶二中的要插入到鍊錶一中的那一部分節點的前驅節點的next成員賦值為null,這樣在就相當於將那一部分節點從鍊錶二中刪除,但是這樣並不會引起記憶體洩漏,這些節點被連線到了鍊錶一的末尾,因此在釋放鍊錶一的時候這些節點依然會被釋放。

4、交換兩個鍊錶的頭結點:

void exchangeline(a_line *head1, a_line *head2)
5、合併鍊錶完整**:
void margeline(a_line *targetline, a_line *resourceline) 

for (srcp = srcprep = resourceline->next; srcp != null; srcp = srcp->next)

else

srcprep = srcp;

} destoryline(resourceline);

}

最後我們給出整體的可測試的**:

#include#include#define not_found	null

typedef struct a_line a_line;

void margeline(a_line *targetline, a_line *resourceline);

a_line *getfirstlocalbiggerthanele(a_line head, a_line ele);

void inserteletoline(a_line *local, a_line ele);

void destoryline(a_line *head);

void initline(a_line *head);

void showline(a_line head);

void exchangeline(a_line *head1, a_line *head2);

a_line *tarp;

for (tarp = targetline.next; tarp->next != null; tarp = tarp->next)

; tarp->next = line;

}void exchangeline(a_line *head1, a_line *head2)

void showline(a_line head)

}void initline(a_line *head)

else

printf("請輸入乙個數(-1表示結束)");

scanf_s("%d", &num); }}

void destoryline(a_line *head)

}void inserteletoline(a_line *local, a_line ele)

a_line *getfirstlocalbiggerthanele(a_line head, a_line ele)

return q;

}void margeline(a_line *targetline, a_line *resourceline)

for (srcp = srcprep = resourceline->next; srcp != null; srcp = srcp->next)

else

srcprep = srcp;

} destoryline(resourceline);

}void main(void) ;

a_line head2 = ;

printf("錄入第乙個鍊錶:\n");

initline(&head1);

printf("錄入第二個鍊錶\n");

initline(&head2);

margeline(&head1, &head2);

printf("鍊錶一:\n");

showline(head1);

printf("鍊錶二:\n");

showline(head2);

destoryline(&head1);

}

將兩個公升序排列的鍊錶合併後公升序排序列印

include include include define len sizeof struct student struct student int n 全域性變數n 用記錄鍊錶的結點數.struct student creat void 建立鍊錶的函式原型宣告.void print struct...

面試題 將兩個公升序排列的鍊錶合併成乙個公升序鍊錶

將兩個公升序排列的鍊錶合併成乙個有序鍊錶 例如 head1 2 3 5 6 7 9 11 head2 2 4 5 7 9 合併之後結果為 head 2 2 3 4 5 5 6 7 7 9 9 11 如下 設head1和head2是兩個非空單向鍊錶,資料值有重複且公升序排序 將head1和head2合...

兩個公升序鍊錶合併成乙個公升序鍊錶

將兩個公升序鍊錶和並成乙個公升序序列 include includetypedef struct node linknode linknode creat linklist2 return h void printlink linknode h linknode mergelink linknode...