雙向鍊錶的歸併排序

2021-07-11 06:28:12 字數 4282 閱讀 9348

歸併排序分為兩個部分:mergesortmerge

mergesort是乙個遞迴函式,在這個函式裡面把待排序的陣列或鍊錶分段,直到每段的長度為1為止。

merge在這個函式中把分開的兩段結合起來,並且在結合的過程中排序

對於乙個陣列用歸併排序是比較方便的,而在對雙向鍊錶用歸併排序時就會發現next/prev指標指向**以及一些邊界問題很麻煩。

下面給出兩種對雙向鍊錶使用歸併排序的方法

linkedlist類的定義

class linkedlist : virtual

public list

} node;

linkedlist(); //這個函式對歸併排序沒什麼用可以無視

~linkedlist(); //這個函式對歸併排序沒什麼用可以無視

virtual

void add(int e); //這個函式對歸併排序沒什麼用可以無視

virtual

void clear(void); //這個函式對歸併排序沒什麼用可以無視

virtual

bool contain(int e); //這個函式對歸併排序沒什麼用可以無視

virtual

bool isempty(void); //這個函式對歸併排序沒什麼用可以無視

virtual

void remove(int e); //這個函式對歸併排序沒什麼用可以無視

virtual

int& operator(int index); //傳入結點序號(從0開始計算)返回第index個結點的data的引用,這個函式會用到

virtual

int& get(int index); //同上,然而這個函式不會被用到

virtual

int indexof(int element); //這個函式對歸併排序沒什麼用可以無視

virtual

void sort(void); //排序(歸併排序)

virtual

int size(void); //這個函式對歸併排序沒什麼用可以無視

private:

node* head; //煉表頭指標

node* tail; //鍊錶尾指標

int _size; //結點總個數

};//下面是virtual int& operator(int index);的定義

int& linkedlist::operator(int index)

return p->data;

}

inline

void mergesort(linkedlist *li, linkedlist::node

*low, linkedlist::node

*high,

linkedlist::node

*head, int i)

mergesort(li, low, mid, head, n); //繼續分離左半部分,此時的low就是上面的low,而high是上面的mid,high(即mid)-low = i/2 = n

mergesort(li, mid->next, high, head, i-n

-1); //分離右半部分,此時的low是mid->next, high就是上面的high,high-low(即mid->next) = i-n-1

merge(li, low, mid, high, i+

1, head); //合併兩部分

}}

inline void merge(linkedlist *li, linkedlist::node *low, linkedlist::node *mid, linkedlist::node *high,  

int size, linkedlist::node *head) else

} //比較兩部分的數字的大小,把小的先輸出到陣列a中

while (p != mid->next) //若第一部分有剩餘則全部輸出到陣列a中

while (q != high->next) //若第二部分有剩餘則全部輸出到陣列a中

while (r != low) 找到low指向的結點的序號,用j記錄

i = 0;

for (k = j; k < j+size; k++) //把陣列a中數字按順序複製到low到high這個區間裡

}

/*接下來在sort中只要寫一句就夠了*/

void linkedlist::sort(void)

這個方法優點在於思考起來比較方便,而且不用改變next/prev指向的位址,缺點在於比較耗時

for (k = j; k < j+size; k++)   //把陣列a中數字按順序複製到low到high這個區間裡

//下面是virtual int& operator(int

index);的定義

int& linkedlist::operator(int

index)

return p->data;

}

可以發現每用一次(*li)[k],都會從頭搜尋一次,當size很大的時候會消耗很多時間,下面提一種優化的方法(雖然只能優化那麼一點點)

/*如果index大於size/2,那麼就從尾部開始搜尋*/

linkedlist::int& linkedlist::operator(int

index)

} else

}return p->data;

}

void linkedlist::sort(void)   //fast一次走兩步,slow一次走一步,當fast到底時,slow就處於中間位置

//從head到slow->prev為一段

li_left.tail = slow->prev;

li_left.tail->next =

null;

//從slow到tail為另一段

li_right.head = slow;

li_right.head->prev =

null;

li_right.tail = this->tail;

li_right._size = this->_size - li_left._size;

this->head =

null;

this->tail =

null;

//繼續對兩段進行分割、排序

li_left.sort();

li_right.sort();

node* pointer_left = li_left.head;

node* pointer_right = li_right.head;

node* pointer_head =

null;

node* pointer_tail =

null;

while (pointer_left !=

null

&& pointer_right !=

null) else //temp指向pointer_left與pointer_right中數值較小的結點

if (pointer_head ==

null) else //把temp接到鍊錶中

pointer_head->prev =

null;

pointer_tail->next =

null;

}while (pointer_left !=

null)

while (pointer_right !=

null)

this->head = pointer_head;

this->tail = pointer_tail;

//注意要把left,right的head,tail指標清空,否則由於是淺拷貝,退出函式棧的時候會把this的空間都釋放。

li_left.head = li_left.tail =

null;

li_right.head = li_right.tail =

null;

}}

這種方法比較高效,可是需要思考的很嚴密,一不小心就會出錯。

鍊錶歸併排序

include include include include include using namespace std typedef int type typedef struct nodetag node node build type a,int n pnode pnext null retu...

鍊錶歸併排序

主要思路 1 如果為null或者只有乙個節點那麼直接返回 2 將鍊錶分成兩部分,分別進行排序,形成兩個有序鍊錶 3 將兩個有序鍊錶合併 void merge sort struct node list void split struct node head,struct node lista,str...

鍊錶 歸併排序

時間複雜度o nlogn 空間複雜度o 1 include include 定義鍊錶 typedef struct listnode linklist linklist head null 建立鍊錶 linklist createlist int arr,int len rear next null...