[Algorithm Learning Diary 01] Top ten rankings

Table of contents

Reference: Top Ten Classic Sorting Algorithms
PS: All codes in this article have been verified through 912 questions (some sorting algorithms will time out): 912. Sorting Arrays

1 Category

Sort categories

2 Algorithm complexity

Sorting method time complexity space complexity stability
Bubble Sort O(n^2) O(1) Stablize
selection sort O(n^2) O(1) unstable
insertion sort O(n^2) O(1) Stablize
Hill sort O(n^1.3) O(1) unstable
Quick sort O(nlogn) O(logn~n) unstable
merge sort O(nlogn) O(n) Stablize
Heap sort O(nlogn) O(1) unstable
counting sort O(n+k) O(n+k) Stablize
bucket sort O(n+k) O(n+k) Stablize
Radix sort O(n*k) O(n+k) Stablize

3 Simple algorithm

3.1 Bubble sort

3.1.1 Algorithm description

Bubble sort is a simple sorting algorithm that repeatedly visits the array to be sorted, compares two elements at a time, and exchanges them if their order does not meet the requirements.

Specifically, taking ascending order as an example, the bubble sort algorithm operates as follows:

1. Compare adjacent elements. If the first one is larger than the second one, swap them two.
2. Do the same for each pair of adjacent elements, starting with the first pair and ending with the last pair. After this step is completed, the final element will be the maximum number.
3. Repeat the above steps for all elements except the last element until there are no pairs of numbers to compare.

3.1.2 GIF demonstration

Bubble Sort

3.1.3 Code implementation

void BubbleSort(int[] nums){
    
    
	for(int i=0;i<nums.Length;i++){
    
    
		bool isOver = true; //剪枝:如果不存在一对数顺序不符合要求,则排序完成
        for(int j=0;j<nums.Length-i-1;j++){
    
    
			if(nums[j]>nums[j+1]){
    
    
            	Swap(nums,j,j+1);
	            isOver = false;
            }
        }
        if(isOver) break;
    }
}

3.1.4 Performance analysis

time complexity space complexity stability
O ( n 2 ) O(n^2)O ( n2) O ( 1 ) O(1)O(1) Stablize

3.2 Simple selection sorting

3.2.1 Algorithm description

Simple selection sort is a simple and intuitive sorting algorithm. Its working principle is to select the smallest/largest element from the data elements to be sorted each time and place it at the starting position of the sequence. Then perform the same steps for the remaining unsorted elements.

Specifically, taking ascending order as an example, the simple selection sort algorithm operates as follows:

1. Initially, the sequence to be sorted is nums[0…n-1].
2. Select the smallest element from the sequence to be sorted and exchange it with the starting bit of the sequence to be sorted.
3. Except for the starting bit, the remaining elements form a new sequence to be sorted. Repeat step 2 until the sequence to be sorted is empty (in fact, you can stop when there is only 1 number left).

3.2.2 GIF demonstration

selection sort

3.2.3 Code implementation

void SelectSort(int[] nums){
    
    
	for(int i=0;i<nums.Length-1;i++){
    
    
		int min = i;
		for(int j=i+1;j<nums.Length;j++){
    
    
			if(nums[j]<nums[min]) min = j;
        }
        if(min!=i) Swap(nums,min,i);
    }
}

3.2.4 Performance analysis

time complexity space complexity stability
O ( n 2 ) O(n^2)O ( n2) O ( 1 ) O(1)O(1) unstable

3.3 Direct insertion sort

3.3.1 Algorithm description

Direct insertion sort is a simple and intuitive sorting algorithm. Its working principle is to construct an ordered sequence. For unsorted data, scan from back to front in the sorted sequence to find the corresponding position and insert it. It can be imagined as playing cards. card management process.

Specifically, taking ascending order as an example, the direct insertion sort algorithm operates as follows:

1. Treat the first element as the initial ordered sequence.
2. Scan from back to front starting from the next bit of the last element in the ordered sequence.
3. If the current element (the element in the sorted sequence) is larger than the new element, move the element one position back.
4. Repeat step 3 until the current element is less than or equal to the new element.
5. Insert the new element after the element.
6. Repeat steps 2~5.

3.3.2 GIF demonstration

insertion sort

3.3.3 Code implementation

void InsertSort(int[] nums){
    
    
	for(int i=1;i<nums.Length;i++){
    
    
    	int temp = nums[i];
        int j;
        for(j=i-1;j>=0;j--){
    
    
        	if(nums[j]>temp) nums[j+1] = nums[j];
            else break;
        }
        nums[j+1] = temp;
    }
}

3.3.4 Performance analysis

time complexity space complexity stability
O ( n 2 ) O(n^2)O ( n2) O ( 1 ) O(1)O(1) Stablize

4 Improved algorithm

4.1 Hill sorting

4.1.1 Algorithm description

Hill sort is a more efficient and improved version of insertion sort. This method is named after DLShell, which was proposed in 1959. Hill sorting groups records by a certain increment of the subscript, and sorts each group using the direct insertion sorting algorithm; as the increment gradually decreases, each group contains more and more keywords. When the increment decreases to 1, The entire sequence is divided into one group, and then direct insertion sorting is performed on all records.

The time complexity of Hill sorting is related to the selection of the incremental sequence, and the average time complexity is O(n^1.3).

4.1.2 GIF demonstration

Hill sort

4.1.3 Code implementation

void ShellSort(int[] nums){
    
    
	int gap = 1;
	//PS:关于为什么是gap*3+1而不是gap*3,据说是因为这样比较符合二进制计算机的特点,能够减少乘法运算的次数,从而提高效率;也有说法是说如果不这样做,算法复杂度可能会降到O(n^2)
    while(gap<nums.Length) gap = gap*3+1;
    while(gap>0){
    
    
    	//直接插入排序
        for(int i=gap;i<nums.Length;i++){
    
    
        	int temp = nums[i];
            int j;
            for(j=i-gap;j>=0;j-=gap){
    
    
            	if(nums[j]>temp) nums[j+gap] = nums[j];
                else break;
            }
            nums[j+gap] = temp;
        }
        gap/=3;
    }
}

4.1.4 Performance analysis

time complexity space complexity stability
O ( N 1.3 ) O(N^{1.3})O ( N1.3) O ( 1 ) O(1)O(1) unstable

4.2 Quick sort

4.2.1 Algorithm description

Quick sort is a sorting algorithm based on the idea of ​​divide and conquer. It continuously divides the array to be sorted into two sub-arrays and sorts the two parts independently.

Specifically, taking ascending order as an example, quick sort operates as follows:

1. Select the pivot element: select an element from the array as the pivot element.
2. Split operation: Place all elements smaller than the base element in front of it, and place all elements larger than the base element behind it.
3. Quickly sort the left and right subarrays recursively.

4.2.2 GIF demonstration

Quick sort

4.2.3 Reference value selection

There are three methods for selecting the base value for quick sort:

1. The endpoint serves as the base value.
2. Random value as base value.
3. Find the middle of three numbers.

Among them, the three-number method is the most commonly used benchmark value selection method. This method first selects the middle digit from the data at the left, mid, and right positions of the array to be sorted as the base value. This can prevent quick sort from degenerating into bubble sort when the array is already sorted or nearly sorted.

4.2.4 Code implementation

1 endpoint as base value
void QuickSort(int[] nums,int left,int right){
    
    
    if(left>=right) return;
    int mid = PartSort(nums,left,right);
    QuickSort(nums,left,mid-1);
    QuickSort(nums,mid+1,right);
}
int PartSort(int[] nums,int left,int right){
    
    
	//最简单的基准值选择:选择待排序数组的第一位元素。
    int pivot = nums[left];
    while(left<right){
    
    
        while(left<right&&nums[right]>=pivot) right--;
        nums[left] = nums[right];
        while(left<right&&nums[left]<=pivot) left++;
        nums[right] = nums[left];
    }
    nums[left] = pivot;
    return left;
}
2 random values ​​as base values
//C# Random实例.Next左闭右开
Random random = new Random();
int index = random.Next(left,right+1);
Swap(nums,index,left);
//Unity Random.Range左闭右开
int index = Random.Range(left,right+1);
Swap(nums,index,left);
3 Method of finding the middle of three numbers
//在int pivot = nums[left]前加上以下代码,使数值居中的值位于left位。
int mid = (left+right)/2;
if(nums[left]>nums[right]) Swap(nums,left,right);
if(nums[mid]>nums[right]) Swap(nums,mid,right);
if(nums[left]<nums[mid]) Swap(nums,left,mid);

4.2.5 Optimization

Optimization 1: When the sequence length reaches a certain size, use insertion sort.

When quick sort reaches a certain depth, the divided interval is very small, and it is not efficient to use quick sort at this time. However, using insertion sort at this time can avoid some harmful degradation situations.

void QuickSort(int left,int right){
    
    
	if(left>=right) return;
	int len = right-left+1;
	if(len<10) InsertSort(left,right);
	else{
    
    
		int mid = PartSort(left,right);
		QuickSort(left,mid-1);
		QuickSort(mid+1,right);
	}
}

Optimization 2: Tail recursion optimization

The quicksort algorithm, like most divide-and-conquer sorting algorithms, has two recursive calls. But quick sort is different from merge sort. The recursion of merge is at the beginning of the function, while the recursion of quick sort is at the end of the function. This allows the quick sort code to implement tail recursion optimization. After using tail recursion optimization, the depth of the stack can be reduced from the original O(n) to O(logn).

Tail recursion
If all recursive calls in a function occur at the end of the function, when the recursive call is the last statement executed in the entire function body and its return value is not part of the expression, the recursive call is tail recursive.

When the compiler detects that a function call is tail recursive, it overwrites the current active record rather than creating a new one on the stack. The compiler can do this because the recursive call is the last statement to be executed in the current active period, so when the call returns there is nothing else to do in the stack frame, so there is no need to save the stack frame. By overwriting the current stack frame instead of adding a new one on top of it, the stack space used is greatly reduced, which makes the actual operation efficiency more efficient.

one example

//线性递归
int fact(int n){
    
    
	if(n<0) return 0;
	else if(n==0||n==1) return 1;
	else n*fact(n-1);
}

When n=5, the recursive process of linear recursion is as follows:

fact(5)
{
    
    5*fact(4)}
{
    
    5*{
    
    4*fact(3)}}
{
    
    5*{
    
    4*{
    
    3*fact(2)}}}
{
    
    5*{
    
    4*{
    
    3*{
    
    2*fact(1)}}}}
{
    
    5*{
    
    4*{
    
    3*{
    
    2*1}}}}
{
    
    5*{
    
    4*{
    
    3*2}}}
{
    
    5*{
    
    4*6}}
{
    
    5*24}
120
//尾递归
int fact(int n,int a){
    
    
	if(n<0) return 0;
	else if(n==0) return 1;
	else if(n==1) return a;
	else return fact(n-1,a*n);
}

When n=5, the recursive process of tail recursion is as follows:

facttail(5,1)
facttail(4,5)
facttail(3,20)
facttail(2,60)
facttail(1,120)
120

It can be seen that tail recursion can reduce the stack depth very well.

Quick Sort Optimization
After the first recursion, the variable left is useless, which means that the second recursion can be replaced by an iterative control structure.

void QuickSort(int left,int right){
    
    
	if(left>=right) return;
	int len = right-left+1;
	if(len<10) InsertSort(left,right);
	else{
    
    
		while(left<right){
    
    
			int mid = PartSort(left,right);
			QuickSort(left,mid-1);
			left = mid+1;
		}
	}
}

4.2.6 Performance analysis

time complexity space complexity stability
O ( n l o g n ) O(nlogn) O(nlogn) O ( l o g n − n ) O(logn-n) O(lognn) unstable

4.3 Merge sort

4.3.1 Algorithm description

Merge sort is a sorting algorithm based on the idea of ​​divide and conquer. It first splits a large array into several small arrays, and then merges them bit by bit. The basic idea of ​​merge sort is to divide the sequence to be sorted into several subsequences, each subsequence is ordered, and then merge the subsequences into an overall ordered sequence.

Specifically, taking ascending order as an example, the merge sort algorithm operates as follows:

1. Divide the sequence to be sorted into several subsequences.
2. Merge adjacent subsequences to obtain several ordered sequences of length 2.
3. Repeat step 2.

4.3.2 The difference between quick sort and merge sort

Both quick sort and merge sort adopt the idea of ​​divide and conquer, and their algorithm time complexity is O(nlogn), but the specific implementation methods are different.

Quick sort is an unstable sorting algorithm. Its basic idea is to divide the column to be sorted into two independent parts through one sorting. The keywords recorded in one part are smaller than the keywords in the other part, and then press this The method continues to sort these two parts of records to achieve the purpose of ordering the entire sequence. Moreover, quick sort is an in-place sorting algorithm that implements sorting by exchanging elements in the array. The space complexity of quick sort depends on the depth of the recursive stack. Generally speaking, the space complexity is O(logn)~O( n).

Merge sort is a stable sorting algorithm that requires additional space to store temporary arrays. The basic idea of ​​merge sort is to divide the sequence to be sorted into several subsequences, each subsequence is ordered, and then merge the subsequences into an overall ordered sequence. The space complexity of merge sort is O(n).

4.3.3 GIF demonstration

merge sort

4.3.4 Code implementation

void MergeSort(int[] nums,int left,int right){
    
    
    if(left>=right) return;
    int mid = (left+right)/2;
    MergeSort(nums,left,mid);
    MergeSort(nums,mid+1,right);
    Merge(nums,left,right);
}
void Merge(int[] nums,int left,int right){
    
    
    int mid = (left+right)/2;
    int i = left;
    int j = mid+1;
    int[] temp = new int[right-left+1];
    int k = 0;
    while(i<=mid&&j<=right){
    
    
        if(nums[i]<=nums[j]) temp[k++] = nums[i++];
        else temp[k++] = nums[j++];
    }
    while(i<=mid) temp[k++] = nums[i++];
    while(j<=right) temp[k++] = nums[j++];
    for(int p=0;p<temp.Length;p++) nums[left+p] = temp[p];
}

4.3.5 Performance analysis

time complexity space complexity stability
O ( n l o g n ) O(nlogn) O(nlogn) O ( n ) O(n)O ( n ) Stablize

4.4 Heap sort

4.4.1 Algorithm description

Heap sort is an in-place sorting algorithm that implements sorting by maintaining a heap. The heap is a special tree data structure that meets the following two conditions:

1. The value of a node in the heap is always no greater than or no less than the value of its parent node.
2. The heap is always a complete binary tree.

The basic idea of ​​heap sorting is to construct the sequence to be sorted into a large root heap or a small root heap, and then remove the top elements of the heap in sequence until the entire sequence is sorted.

Specifically, taking ascending order as an example, the heap sort algorithm operates as follows:

1. Build a heap: Construct the initial sequence of keywords to be sorted (R1, R2….Rn) into a large top heap. At this time (R1, R2….Rn) is the initial unordered area.
2. Exchange: Exchange the top element R[1] with the last element R[n], and get a new unordered area (R1, R2,...Rn-1) and a new ordered area (Rn). , and satisfy R[1,2…n-1]<=R[n];
3. Adjust the heap: Since the new heap top R[1] after the exchange may violate the properties of the heap, it is necessary to adjust the current unordered area ( R1, R2,...Rn-1) is adjusted to the new heap, and then R[1] is exchanged with the last element of the unordered area again to obtain a new unordered area (R1, R2...Rn-2) and a new Ordered area (Rn-1,Rn). This process is repeated until the number of elements in the ordered area is n-1, then the entire sorting process is completed.

4.4.2 GIF demonstration

Insert image description here

4.4.3 Code implementation

Knowledge points:

父:i -> 子:2i+1/2i+2
子:i ->:(i-1)/2
void HeapSort(int[] nums){
    
    
    CreateHeap(nums);
    for(int i=nums.Length-1;i>0;i--){
    
    
        Swap(nums,0,i);
        AdjustHeap(nums,0,i-1);
    }
}
void CreateHeap(int[] nums){
    
    
    int last = nums.Length-1;
    for(int i=(last-1)/2;i>=0;i--){
    
    
        AdjustHeap(nums,i,last);
    }
}
void AdjustHeap(int[] nums,int left,int right){
    
    
    int root = left;
    int child = root*2+1;
    while(child<=right){
    
    
        if(child+1<=right&&nums[child]<nums[child+1]) child++;
        if(nums[root]>=nums[child]) return;
        else{
    
    
            Swap(nums,root,child);
            root = child;
            child = root*2+1;
        } 
    }
}

4.4.4 Performance analysis

time complexity space complexity stability
O ( n l o g n ) O(nlogn) O(nlogn) O ( 1 ) O(1)O(1) unstable

5 other algorithms

5.1 Counting sort

5.1.1 Algorithm description

The core of counting sorting is to convert the input data into an array subscript and store it in an additional opened array space. It requires that the input data must be a positive integer with a certain range.

Specifically, taking ascending order as an example, the counting sort algorithm operates as follows:

1. Find the maximum value max and minimum value min from the unordered sequence, and determine the size of the additional array space: int[] temp = new int[max-min+1].
2. Traverse the original array, count the number of occurrences of each value in the array, and record it in the array newArr.
3. Improve the statistics array: Each item in the statistics array is the sum of the counts from newArr to the current item.
4. Reverse padding.

5.1.2 GIF demonstration

counting sort

5.1.3 Code implementation

void CountSort(int[] nums){
    
    
	//1.找最大最小值以确定额外开辟的数组空间的大小
	int min = nums[0];
	int max = nums[0];
	for(int i=1;i<nums.Length;i++){
    
    
		if(nums[i]<min) min = nums[i];
		if(nums[i]>max) max = nums[i];
	}
	int[] newArr = new int[max-min+1];
	for(int i=0;i<nums.Length;i++){
    
    
		newArr[nums[i]-min]++;
	}
	//2.统计数组-为保证排序稳定
	int[] countArr = new int[newArr.Length];
	for(int i=0;i<newArr.Length;i++){
    
    
		if(i==0) countArr[i] = newArr[i];
		else countArr[i] = newArr[i]+countArr[i-1];
	}
	//3.最终结果
	int[] result = new int[nums.Length];
	for(int i=nums.Length-1;i>=0;i--){
    
    
		result[countArr[nums[i]-min]-1] = nums[i];
		countArr[nums[i]-min]--;
	}
}

5.1.4 Performance analysis

time complexity space complexity stability
O ( n + k ) O(n+k) O ( n+k) O ( n + k ) O(n+k)O ( n+k) Stablize

5.2 Bucket sorting

5.2.1 Algorithm description

Bucket sort is an upgraded version of counting sort. It makes use of the mapping relationship of functions. The key to efficiency lies in the determination of this mapping function.

The working principle of Bucket sort: Assume that the input data obeys a uniform distribution, divide the data into a limited number of buckets, and then sort each bucket separately (it is possible to use other sorting algorithms or continue to use it recursively) bucket sorting).

Specifically, taking ascending order as an example, the bucket sort algorithm operates as follows:

1. First find the maximum value max and minimum value min in all data.
2. Determine the size of the bucket: Determine the range of data contained in each bucket based on max and min, size = (max-min)/n+1, n is the number of data, you need to ensure that there is at least one bucket, so you need Add 1.
3. Determine the number of buckets: After finding the size, you know the range of data contained in each bucket. You also need to calculate the required number of buckets cnt, cnt = (max-min)/size+1, and you need to ensure Each bucket must be able to hold at least 1 number, so you need to add 1.
4. After obtaining size and cnt, we know that the data range of the first bucket is [min, min+size), the second bucket is [min+size, min+2*size),..., and so on.
5. To sort the data in each bucket, you can use bucket sorting recursively or use other sorting methods.
6. Output the ordered sequences in each bucket in sequence.

5.2.2 Code implementation

void BucketSort(int[] nums){
    
    
    //1.找最小值和最大值以计算size和cnt
    int min = nums[0];
    int max = nums[0];
    for(int i=1;i<nums.Length;i++){
    
    
        if(nums[i]<min) min = nums[i];
        if(nums[i]>max) max = nums[i];
    }
    int n = nums.Length;
    int size = (max-min)/n+1;
    int cnt = (max-min)/size+1;
    List<int>[] bucket = new List<int>[cnt];
    for(int i=0;i<cnt;i++){
    
    
        bucket[i] = new List<int>();
    }
    //2.扫描数组,将元素放进对应的桶里
    for(int i=0;i<nums.Length;i++){
    
    
        int index = (nums[i]-min)/size;
        bucket[index].Add(nums[i]);
    }
    //3.对各个桶进行排序
    for(int i=0;i<cnt;i++){
    
    
        bucket[i].Sort();
    }
    //4.反向填充
    int m = 0;
    for(int i=0;i<cnt;i++){
    
    
        for(int j=0;j<bucket[i].Count;j++){
    
    
            nums[m++] = bucket[i][j];
        }
    }
}

5.2.3 Performance analysis

time complexity space complexity stability
O ( n + k ) O(n+k)O ( n+k) O ( n + k ) O(n+k)O ( n+k) Stablize

5.3 Radix sort

5.3.1 Algorithm description

Radix sort is a non-comparative integer sorting algorithm. Its principle is to cut the integer into different numbers according to the number of digits, and then compare each digit separately. The radix sorting method can be LSD (Least significant digital) or MSD (Most significant digital). The sorting method of LSD starts from the rightmost of the key value, while the MSD sorting method starts from the leftmost of the key value.

Specifically, taking ascending order as an example, the radix sorting algorithm operates as follows:

1. Find the maximum number in the array and determine the number of digits.
2. Starting from the lowest bit, each bit forms a radix array.
3. Sort the radix array by count.

5.3.2 GIF demonstration

Radix sort

5.3.3 Code implementation

void RadixSort(int[] nums) {
    
    
	//1.准备桶
    int[,] bucket = new int[10, nums.Length];
    int[] bucketCount = new int[10];
    //2.获取最大数的位数
    int max = nums[0];
    for(int i = 1; i < nums.Length; i++) {
    
    
    	if (nums[i] > max) max = nums[i]; 
    }
    int len = (max + "").Length;
    //3.桶排序
    int arrCount;  //原始数组索引
    for(int k = 0, n = 1; k < len; k++, n *= 10) {
    
    
    	//3.1 第k轮桶排序
        for(int i = 0; i < nums.Length; i++) {
    
    
        	int digit = nums[i] / n % 10;  //获取个十百千万数
            bucket[digit,bucketCount[digit]] = nums[i];
            bucketCount[digit]++;
        }
        //3.2 将桶中数据取出来给原数组
        arrCount = 0;
        for(int i = 0; i < 10; i++) {
    
    
        	if (bucketCount[i] != 0) {
    
    
            	for(int j = 0; j < bucketCount[i]; j++) {
    
    
                	nums[arrCount++] = bucket[i, j];
                }
                }
            }
        //3.3 清空桶
        bucketCount = new int[10];
   }
}

5.3.4 Performance analysis

time complexity space complexity stability
O ( n ∗ k ) O(n*k) O ( nk) O ( n + k ) O(n+k) O ( n+k) Stablize

6 List sorting method

6.1 Sorting method

list.Sort();      //升序方法
list.Reverse();   //降序方法
list.OrderBy(x=>x.MyProperty); //OrderBy接受一个Lambda表达式指定要按其排序的键

6.2 Rewrite the sorting method

6.2.1 x.CompareTo(y)

int result = a.CompareTo(b);

If a=b, then result=0; if a>b, then result=1; if a<b, then result=-1.

6.2.2 Rewrite

1 Custom comparator
class CustomComparer : IComparer<MyClass>{
    
    
	public int Compare(MyClass x,MyClass y){
    
    
		return x.MyProperty.CompareTo(y.MyProperty);
	}
}

list.Sort(new CustomComparer());
2 Lambda
list.Sort((x,y)=>x.MyProperty.CompareTo(y.MyProperty));
3 Anonymous delegation
list.Sort(delegate(MyClass x,MyClass y){
    
    
	if(x.MyProperty>y.MyProperty) return 1;
	else return -1;
});

7 exercises

912 Sorted Array

A little bit can be used to practice sorting by hand.

56 merge interval

public class Solution {
    
    
    public int[][] Merge(int[][] intervals) {
    
    
        //1.依据左端点进行排序
        Array.Sort(intervals,(x,y)=>x[0].CompareTo(y[0]));
        //2.合并重叠区间
        List<int[]> list = new List<int[]>();
        list.Add(intervals[0]);
        for(int i=1;i<intervals.Length;i++){
    
    
            int[] temp = list[list.Count-1];
            if(temp[1]>=intervals[i][0]){
    
    
                temp[1] = Math.Max(temp[1],intervals[i][1]);
            }else{
    
    
                list.Add(intervals[i]);
            }
        }
        return list.ToArray();
    }
}

148 Sorted linked list

1 Find the midpoint of the linked list - fast and slow pointers

ListNode FindMidNode(ListNode head){
    
    
	if(head==null||head.next==null) return head;
    ListNode fast = head;
    ListNode slow = head;
    while(fast.next!=null){
    
    
    	if(fast.next.next==null) return slow;
        else fast = fast.next.next;
        slow = slow.next;
    }
    return slow;
}

2 Merge two ordered linked lists

ListNode Merge(ListNode list1,ListNode list2){
    
    
	if(list1==null) return list2;
    if(list2==null) return list1;
    if(list1.val>list2.val) return MergeTwoLists(list2,list1);
    list1.next = MergeTwoLists(list1.next,list2);
    return list1;
}

3 Summary

public class Solution {
    
    
    public ListNode SortList(ListNode head) {
    
    
        if(head==null||head.next==null) return head;
        ListNode mid = MiddleNode(head);
        ListNode temp = mid.next;
        mid.next = null;
        ListNode list1 = SortList(head);
        ListNode list2 = SortList(temp);
        return MergeTwoLists(list1,list2);
    }
    //辅助方法1:找到链表的中间结点(当中间结点有两个时,返回前面的那个)
    private ListNode MiddleNode(ListNode head){
    
    
        if(head==null||head.next==null) return head;
        ListNode fast = head;
        ListNode slow = head;
        while(fast.next!=null){
    
    
            if(fast.next.next==null) return slow;
            else fast = fast.next.next;
            slow = slow.next;
        }
        return slow;
    }
    //辅助方法2:合并两个有序链表
    private ListNode MergeTwoLists(ListNode list1,ListNode list2){
    
    
        if(list1==null) return list2;
        if(list2==null) return list1;
        if(list1.val>list2.val) return MergeTwoLists(list2,list1);
        list1.next = MergeTwoLists(list1.next,list2);
        return list1;
    }
}

Guess you like

Origin blog.csdn.net/manpi/article/details/129856032