歸併排序分為兩個部分:mergesort
和merge
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...