リストをソート
0ソース
出典:滞在ボタン(LeetCode)
トピックリンクします。https://leetcode-cn.com/problems/sort-list
1.タイトル説明
複雑さと一定のグレードの空間的な複雑さは、時間(N Nログ)Oにリンクリストを並べ替えられています。
2.テストケース
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
3.問題解決のアイデア
3.1一般的な考え方
リストはソートを参照してください、私の最初の反応は、私は問題を解決するこのアイデアを持っている主な理由は、私が選択ソートであるか、何を感じるの時間の複雑さとスペースの複雑さを話さないだろう、達成することができるはずです挿入ソートは、リストの並べ替えを達成することができるはずです
話は安い私のコードを示します。..
まあ、擬似コード。(私は達成するためにJavaを使用するので、私は主に、Javaプログラミングを使用しているので)
while(没有到最后一个节点){
Node cursorNode = currentNode.next;
while( cursorNode != null){
把找到比第一层循环节点的小的节点与它进行交换
cursorNode = cursorNode.next;
}
}
それはおそらくケースで、選択、ソート、ほぼ達成しました。
しかし、対象を見て:時間計算の複雑さのOの必要性(N Nログ)空間の一定のレベル、時間計算量が必要とされ、マージソートを思い出させる、見た目も考え出したが、配列の上に見えていませんここLeetCodeその明晰な思考上の問題とマージソートの大物を解決するには、基本的なアイデアのマージソートであります
3.2説明マージソートのアイデア
3.2.1基本的な考え方
全体的な一般化は、下から上へ、上から下へ再帰的に分割され、その後徐々に合流します。
- 再帰分割:
左右のサブシーケンスにソートされる最初のアレイは、2つの左右の配列は、4つのサブシーケンスに分割され、従って二つまたは遠くに配列の要素の最小数までオン。
- 徐々にマージ:
ソート左端のサブシーケンスの底部は、2つの配列を合わせ、左から右、次に下1/3に、順序付けられたソート、右及び第二サブ左から順序付けされますアレイ内のソート操作の合併が完了した後.....サブソートメモリ(合成、再帰的階層リターンとして理解することができるから階層に注意を払う必要があります)
3.2.2アルゴリズムステップ
- 宇宙アプリケーションなので、2つのソート順序、合併を格納するために使用される配列スペースの合計の大きさという。
- 、それぞれ、2つのソートシーケンスの開始位置の最初の位置を二つのポインタを設定します。
- 要素には、2つのポインタポイントの比較、比較的小さなスペースに選択された要素は、マージ、および次の位置にカーソルを移動させます。
- ポインタを繰り返しステップ3は、配列の一方の端部に到達します。
- 別のシーケンスの残りのすべての要素は、直接シーケンスのマージにコピー。
3.2.3動的なプレゼンテーション
3.2.4アルゴリズムのプロパティ
そして、選択入力データによって影響を受けるパフォーマンスのマージソートなどのソート、が、常にO(nlogn)時間複雑であるとしてパフォーマンスは、より良い選択ソートを超えています。追加のメモリ空間のコストが必要とされています。
3.2.5コードショー
/**
* 递归拆分
* @param arr 待拆分数组
* @param left 待拆分数组最小下标
* @param right 待拆分数组最大下标
*/
public static void mergeSort(int[] arr, int left, int right) {
int mid = (left + right) / 2; // 中间下标
if (left < right) {
mergeSort(arr, left, mid); // 递归拆分左边
mergeSort(arr, mid + 1, right); // 递归拆分右边
sort(arr, left, mid, right); // 合并左右
}
}
/**
* 合并两个有序子序列
* @param arr 待合并数组
* @param left 待合并数组最小下标
* @param mid 待合并数组中间下标
* @param right 待合并数组最大下标
*/
public static void sort(int[] arr, int left, int mid, int right) {
int[] temp = new int[right - left + 1]; // 临时数组,用来保存每次合并年之后的结果
int i = left;
int j = mid + 1;
int k = 0; // 临时数组的初始下标
// 这个while循环能够初步筛选出待合并的了两个子序列中的较小数
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
// 将左边序列中剩余的数放入临时数组
while (i <= mid) {
temp[k++] = arr[i++];
}
// 将右边序列中剩余的数放入临时数组
while (j <= right) {
temp[k++] = arr[j++];
}
// 将临时数组中的元素位置对应到真真实的数组中
for (int m = 0; m < temp.length; m++) {
arr[m + left] = temp[m];
}
}
3.3マージソート・リスト上のご注意
中間ノードを見つけ1
ソリューション:間違いなく、背面に移動するには、このメソッドが完了するまで遅い速いスピードデュアルユース[]のポインタで、かつ、実際には、原則的には高価なサウンドで、特に簡単素晴らしいですが、すべての動きが後方一つであり、他の2二回最後の最初のポインタの高速と低速のポインタ。これとランニングは、二回あなたの速度がある人かのように、同時に、彼は二回あなたの旅でなければなりません。
奇数、中間ノードが中間である場合、それは中間ノードの偶数である場合、ノードの中間ノードの数も、分離することができ、実際には、中間位置の前に中間ノードとしてそれを遅くするポインタノードです。
2は、それぞれ、中間ノードから切り離され、これら二つのリストを並び順
ポインタがnullに設定されているリストの右のように開始ノードを押したままにするノードと次のノードを遅くし、次のポインタを遅くすることです:どのように切断するには
4.コードの実装
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
public class LinkListSort {
public static ListNode sortList(ListNode head) {
// 设置递归终止条件:如果是一个节点,或者是 null 就可以返回
if ( head == null || head.next == null)
{
return head;
}
// 通过 快慢双指针 来寻找链表分割的点
ListNode slowNode = head;
ListNode fastNode = head.next;
while (fastNode!=null && fastNode.next!=null)
{
slowNode = slowNode.next;
fastNode = fastNode.next.next;
}
// 设置右部分链表的开始部分
ListNode temp = slowNode.next;
// 从中间断开链表
slowNode.next = null;
ListNode leftNode = sortList((ListNode) head);
ListNode rightNode = sortList((ListNode) temp);
//设置一个新的头节点来保存排序后的效果
ListNode cursorNode = new ListNode(0);
ListNode resNode = cursorNode;
// 对两个链表进行排序
while ( leftNode!=null && rightNode!=null)
{
if(leftNode.val < rightNode.val)
{
cursorNode.next= leftNode;
leftNode = leftNode.next;
}else{
cursorNode.next = rightNode;
rightNode = rightNode.next;
}
// 将指针节点向后移动
cursorNode = cursorNode.next;
}
// 判断两条链表是否循环到结尾,如果没循环到结尾将未循环完的挂在上面
cursorNode.next = leftNode == null ? rightNode : leftNode;
return resNode.next;
}
public static void main(String[] args) {
ListNode head = new ListNode(4);
ListNode a = new ListNode(2);
ListNode b = new ListNode(1);
ListNode c = new ListNode(3);
head.next =a;
head.next.next = b;
head.next.next.next=c;
ListNode listNode = sortList2( head);
while ( listNode!=null )
{
System.out.print(listNode.val+" ");
listNode = listNode.next;
}
}
}
5.まとめ
1.速い遅いと2ポインタを学び、
利点だけでなく、マージソート2.上記ポインタはそう単純なアルゴリズムをソートリストに合わせた無駄な空間配列は、存在しない、スペースには適用されません。