[Sort] merge class sort - merge sort (the number of questions in reverse order)

Micro-channel public number: bigsai
Data Structures and Algorithms column

Foreword

In sorting, we may be more familiar to most of the bubble sort, quick discharge and the like. To merge sort may be unfamiliar. But in fact merge sort is also a stable sort, time complexity is O (nlogn).

Merge sort is performed based on the partition merge, there are way merge and merge multiple. Here we talk about Merging and daily use is the basic way merge. And merge sort implementation has 递归形式and 非递归形式. Important to distinguish between them (there are no major ideological differences, but there will distinguish contrast behind the division).

And a merge sort very important application is seeking the number of reverse number in the sequence. Of course, in reverse order number can also be used Fenwick tree is complete, not presented here.

Merge sort (merge sort)

Merge and quick discharge are divide and conquer algorithm is. Divide and conquer algorithm is actually a lot of applications, many will use recursive divide and conquer, there are a lot of recursive algorithm is divide and conquer, but in fact divide and conquer and recursion are two things . Partition is divide and rule. Because the face of the sort, if you do not adopt a reasonable policy. Each one more number will have a huge impact on the whole as a whole. The partition that the whole problem can be broken down into similar sub-problems. To solve the sub-problems is much more efficient than the entire solution to the problem, and the problem child of the merger does not take up too much resources.

As for the idea of ​​merging is this:

  • First: the whole string to be divided into a single one, a first time eleven ( 12 34 56---) merge into pairs, divided into two sections merge End (. xx xx xx xx----) Such a sequence of local order.
  • The second is to merge into a number of four twenty-two ( 1234 5678 ----) for each small part is ordered .
  • So until this last only a string, but this takes the total number of logn. Every time a complex operation again O(n). So the total time complexity is O(nlogn).

For the partition process you may know, but this twenty-two mergeprocess is actually very important. First two sequences until we are ordered. In fact, very simple idea, assume that two strings to 3 5 7 8and 2 6 9 10perform merge operations. We need the help of an additional array of team[8]two strings of deposit into an orderly line. The process is this:
Here Insert Picture Description

Non-recursive merge
properly merge the code that implements all means recursive. But there are also without the aid of recursion. Most textbooks or exams if you make a sequence of columns merge, then the default is non-recursive , such a sequence 9,2,6,3,8,1,7,4,10,5is divided sequence is the same.

第一次结束: {2,9}{3,6}{1,8}{4,7}{5,10}
第二次结束:{2,3,6,9}{1,4,7,8}{5,10}
第三次结束:{1,2,3,4,6,7,8,9}{5,10}
第四次结束:{1,2,3,4,5,6,7,8,9,10}

Recursive merge
merge on the implementation of the code may be mostly recursive merge. And recursive divide and conquer and the whole together is really very easy to understand. Recursive problem can be broken down into sub-problems, and this is precisely the means needed points legacy. The recursive a return to the process 来(分治)回(归并), everything is just right.

The idea of recursive and non-recursive above certainly different, you can think about non-recursive: I have to consider several current carried merge, each coordinate of the start of the head indicate how, but also consider whether cross-border Kazakhstan and so on, to write a little trouble .

Rather it is a recursive process is the 局部—>整体process, and is a recursive 整体—>局部—>整体process.
The Recursive merge ideas:

 void mergesort(int[] array, int left, int right) {
		int mid=(left+right)/2;//找到中间节点
		if(left<right)//如果不是一个节点就往下递归分治
		{
			mergesort(array, left, mid);//左区间(包过mid)进行归并排序
			mergesort(array, mid+1, right);//右区间进行归并排序
			merge(array, left,mid, right);//左右已经有序了,进行合并
		}
	}

The same is 9,2,6,3,8,1,7,4,10,5such a bunch of sequence, the order of its recursive implementation is such that (probably part of the problem a little, but still helps to understand):
Here Insert Picture Description

So to achieve a merge sort of code:

private static void mergesort(int[] array, int left, int right) {
		int mid=(left+right)/2;
		if(left<right)
		{
			mergesort(array, left, mid);
			mergesort(array, mid+1, right);
			merge(array, left,mid, right);
		}
	}

	private static void merge(int[] array, int l, int mid, int r) {
		int lindex=l;int rindex=mid+1;
		int team[]=new int[r-l+1];
		int teamindex=0;
		while (lindex<=mid&&rindex<=r) {//先左右比较合并
			if(array[lindex]<=array[rindex])
			{
				team[teamindex++]=array[lindex++];
			}
			else {				
				team[teamindex++]=array[rindex++];
			}
		}
		while(lindex<=mid)//当一个越界后剩余按序列添加即可
	      {
	    	  team[teamindex++]=array[lindex++];
	    	  
	      }
		while(rindex<=r)
	      {
	    	  team[teamindex++]=array[rindex++];
	      }	
		for(int i=0;i<teamindex;i++)
		{
			array[l+i]=team[i];
		}
		
	}

Reverse Number

We must first understand what is the number of reverse order:

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对

也就是比如3 2 1.看3 ,有2 1在后面,看2 有1在后面有3个逆序数。
而比如1 2 3的逆序数为0.

在数组中,暴力确实可以求出逆序数,但是暴力之法太复杂,不可取!而有什么好的方法能解决这个问题呢? 当前序列我可能不知道有多少序列。但是我们直到如果这个序列如果有序那么逆序数就为0.

在看个序列 abcd 3 2 1 efg编程abcd 1 2 3 efg整个序列逆序数减少3个。因为如果不管abcd还是efg和123三个数相对位置没有变。所以我们是可以通过某种方法确定逆序数对的。

我们就希望能不能有个过程,动态改变如果逆序数发生变化能够记录下来?!比如动那么一下能够知道有没有改变的。并且这个动不能瞎动,最好是局部的,有序的动。归并排序就是很适合的一个结构。因为肯定要选个小于O(n2)的复杂度算法,而归并排序满足,并且每次只和邻居进行归并,归并后该部分有序。

纵观归并的每个单过程例如两个有序序列:假设序列2 3 6 8 9和序列1 4 7 10 50这个相邻区域进行归并。

Here Insert Picture Description
而纵观整个归并排序。变化过程只需要注意一些相对变化即可也就是把每个归并的过程逆序数发生变化进行累加,那么最终有序的那个序列为止得到的就是整个序列的逆序数!
Here Insert Picture Description

As for the law, you can find each merging process, the number of reverse and only if the number of advance into the right side of the left, but the number has not been placed on the left is to reduce the element when! The need to digest it, and in the code implementation, need to be!

int value;
------
-----
------
private static void merge(int[] array, int l, int mid, int r) {
		int lindex=l;int rindex=mid+1;
		int team[]=new int[r-l+1];
		int teamindex=0;
		while (lindex<=mid&&rindex<=r) {
			if(array[lindex]<=array[rindex])
			{
				team[teamindex++]=array[lindex++];
			}
			else {				
				team[teamindex++]=array[rindex++];
				value+=mid-lindex+1;//加上左侧还剩余的
			}
		}
		while(lindex<=mid)
	      {
	    	  team[teamindex++]=array[lindex++];
	    	  
	      }
		while(rindex<=r)
	      {
	    	  team[teamindex++]=array[rindex++];
	      }	
		for(int i=0;i<teamindex;i++)
		{
			array[l+i]=team[i];
		}
		
	}

Epilogue

As to merge sort in reverse order and the number of talk so much! Personal feeling has tried to speak, and if there is an error or a bad place also please correct me. If you feel you can also please thumbs up, focus on a Bo Ha.
No welcome public attention: bigsailong-term struggle output!

He published 192 original articles · won praise 1768 · Views 600,000 +

Guess you like

Origin blog.csdn.net/qq_40693171/article/details/104077051