鏈表是最爲常見,而且常常須要使用到的數據結構之一。對於單鏈表的基本操做,例如建立鏈表、插入、刪除等都不是特別複雜,可是其實對於鏈表的操做實際上不少的操做仍是有必定的難度,例如上次給出的單鏈表的逆轉,以及這裏的單鏈表交換兩個節點。 node
單鏈表的交換節點的含義是:給定一個單鏈表,要求交換其中的任意兩個節點。注意這裏鏈表的頭節點是不參與節點交換的。這個看上去是比較簡單,可是實現起來卻仍是須要必定的基本功。 ios
對於這個問題,關鍵是要用4個指針來保存兩個交換的節點的先後節點位置,具體實現請參見實現源碼。實際上,還有一個邏輯更加清晰的實現:只要用兩個指針保存當前的兩個交換節點的前一個節點,而後依次刪除待交換節點,再在記錄的前一個節點後交替插入刪除的兩個節點,也就是實際上將這個過程轉化爲了對於鏈表的兩個基本操做就能夠完成了。可是要注意的是,這個實現中當兩個交換節點是相鄰節點的時候會出現問題,要單獨處理,具體緣由手工操做一次便可得知。後一種方法這裏就不給出了。 數據結構
實現代碼中要說明的是,交換鏈表節點傳入的是兩個交換節點指針,可是爲了測試簡單實現,將這兩個節點換成了待交換節點的關鍵字(值域),再到鏈表中定位。 函數
//Link.h #include <iostream> #include <ctime> struct Node { public: Node():_val(0),_next(NULL) { } Node(int val):_val(val),_next(NULL) { } Node(int val,Node* next):_val(val),_next(next) { } ~Node() { if (_next) delete _next; } public: int _val; Node* _next; }; typedef Node* LinkNode; Node* CreateLink(int len,int MAX_BOUND = 100) { srand((unsigned int)time(NULL)); LinkNode head = new Node(-1); LinkNode tmp = head; for (int i = 0; i < len; ++i) { //tmp = tmp->_next = new Node(rand() % MAX_BOUND); tmp = tmp->_next = new Node(i); } tmp->_next = NULL; return head; } void ExchLinkNode(const LinkNode head,const LinkNode node1,const LinkNode node2) { //head不許被交換 LinkNode prenode1 = NULL; //保存待交換節點node1的前一個節點 LinkNode postnode1 = NULL; //保存待交換節點node1的後一個節點 LinkNode prenode2 = NULL; //保存待交換節點node2的前一個節點 LinkNode postnode2 = NULL; //保存待交換節點node2的後一個節點 LinkNode tmp = head; //不得和頭節點交換 if (node1 == head) { return ; } else if (node2 == head) { return ; } //本身和本身就沒必要交換了 if (node1 == node2) { return ; } //節點相鄰狀況處理 if (node1->_next == node2) { tmp = head; while (tmp->_next != node1) { tmp = tmp->_next; } prenode1 = tmp; postnode2 = node2->_next; prenode1->_next = node2; node2->_next = node1; node1->_next = postnode2; return ; } if (node2->_next == node1) { tmp = head; while (tmp->_next != node1) { tmp = tmp->_next; } prenode2 = tmp; postnode1 = node1->_next; prenode2->_next = node1; node1->_next = node2; node2->_next = postnode1; return ; } tmp = head; while (tmp->_next != node1) { tmp = tmp->_next; } prenode1 = tmp; tmp = head; while (tmp->_next != node2) { tmp = tmp->_next; } prenode2 = tmp; postnode1 = node1->_next; postnode2 = node2->_next; //交換節點 prenode1->_next = node2; node2->_next = postnode1; prenode2->_next = node1; node1->_next = postnode2; }
總結鏈表節點交換時候至少須要考慮的狀況有(這裏不進行必要的參數驗證): post
1) 鏈表頭節點不參與任何交換; 測試
2) 節點相同就沒必要進行交換; spa
3) 節點相鄰的時候要特殊處理。 指針
之因此對單鏈表的節點交換做了較多的描述,是由於單鏈表的節點交換做是鏈表排序中 code
的基本操做,具體將在相應的實現中描述。所以這裏給出的交換節點函數傳入的直接就是鏈表和兩個節點,若是傳入的是節點的關鍵字,先遍歷鏈表定位就能夠了,相關數據結構的定義參見《單鏈表操做——交換節點》。 orm