鏈表的排序


本次討論單向鏈表的排序。本質上講,鏈表的排序與數組的排序在算法上有很多相通的地方,但是由於單向鏈表只能向后訪問的特殊性,那些要求隨機訪問的排序算法在鏈表的排序上並不能施展手腳,所以只能采用相鄰比較的排序方法:冒泡法,而且只能從前向后冒泡。鏈表的另一個問題是由於長度不是已知的,所以終止條件只能通過節點是否為空進行判斷,而每次的循環次數也是如此。下面是兩種排序方法,一種求出長度再排序,另一種直接進行排序。

另一種排序要求是倒序。當然,我們可以修改count1(),使其不分青紅皂白總是交換相鄰節點,只是復雜度較高。另一種優美簡練的算法就是下面的reverse方法。代碼中添加了注釋,應該能看明白。核心思想就是化整為零,每次把即將要倒序的節點指向已倒序完成的節點序列,然后指針右移,直至結束。

    // 計算鏈表長度
public int count() {
	Node2<T> temp = head;
	int count = 0;
	while (temp != null) {
		count++;
		temp = temp.next;
	}
	return count;
}

// 用於兩節點數據交換
private void swap(Node2<T> Node21, Node2<T> Node2) {
	T temp = Node21.key;
	Node21.key = Node2.key;
	Node2.key = temp;
}

// 由鏈表長度控制循環判斷條件
public void sort1() {
	int n = count();
	if (n > 1) {// 至少兩個節點才能排序;
		for (int i = 0; i < n; i++) {
			Node2<T> temp = head;
			for (int j = 0; j < n - i - 1; j++) {// 相鄰比較,前者小則互換值。(升序排列)
				if (((Person) temp.key).compareTo((Person) temp.next.key) == 1)
					swap(temp, temp.next);
				temp = temp.next;// 指針右移
			}
		}
	}
}

// 此處維護兩個指針,index記錄外層循環的起始位置,每次右移;temp和sort1()方法里的temp指針作用一致,表示內層循環。
public void sort2() {
	Node2<T> index = head;
	while (index != null) {
		Node2<T> temp = index;
		while (temp != null && temp.next != null) {
			if (((Person) temp.key).compareTo((Person) temp.next.key) == -1)
				swap(temp, temp.next);
			temp = temp.next;
		}
                    // 注意此處,由於鏈表只能向右訪問,導致最值只能冒向右側。我們的外層循環指針之所以也是右移,是因為下面對頭節點和尾節點進行了互換,使得最 值相當於冒向左側。
		swap(index, temp);
		index = index.next;
	}
}

  //此處為鏈表的反轉操作,邏輯存在一定難度,但已是我見過的精煉優美的代碼
   public ListNode reverse(ListNode head) {
	ListNode  result = null;聲明一個鏈表
	while(head != null){
		ListNode temp = head.next;(1)//因下一步要修改head.next,(1)將右移指針保存起來,(4)最后再給head;
		head.next = result;(2)//(2)就是把下一個等待倒序的節點(head)指向已經倒序完成的result節點,這樣又有一個節點完成了倒序;
		result = head;(3)//(3)把結果重新指向最新的倒序節點序列;
		head = temp;(4)//指針右移;
	}
	return result;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM