Merge and Sort -- Array Realization, Link List Realization, Inverse Ordinal Number

Posted by mithril on Fri, 13 Sep 2019 09:00:15 +0200

Listening to the name, I think it's a tall sort. It took me an hour to learn what merge sort is today.

Of course, I searched a lot of blogs. The reason why I want to learn juxtaposition is that Mr. Xu was asked to write a list of nlog(n) when he was absent-minded during the interview. Mr. Xu wrote it out, but I was confused, so I always wanted to learn.

 

Typing more code will do.

 

The following are from: https://blog.csdn.net/FDk_LCL/article/details/90581741

Algorithmic representation:


The basic principle of merging and sorting is to merge two (or more) ordered tables into a new ordered table, that is, to divide the sequence to be sorted into several sub-sequences, each of which is ordered. Then the ordered subsequences are merged into the whole ordered sequence. In fact, generally speaking, for a number itself is ordered, then each time two numbers are selected to make its own order, and then each time four numbers are selected to make its own order, and then double the growth of the choice, sorting. If two ordered tables are combined into one ordered table, they will be merged into two routes. (Specifically, it can be analyzed according to the following figure)

Analysis of algorithm execution process:


For example: 15, 2, 35, 6, 23, 11, 5
Description: s1, s2, E1 and E2 represent the first and last positions of two merged segments, brr [] is an auxiliary array and arr [] is an array for storing results.
Specific steps:


Learning comes from: https://blog.csdn.net/FDk_LCL/article/details/90581741

Array form

Recursion is replaced by loops, but not for linked lists

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
void Merge(int *arr,int len,int gap)
{
	int *brr = (int *)malloc(sizeof(int) * len);  //Dynamic pioneering auxiliary array
	assert(brr != NULL);
	int i = 0;           //Subscript of brr
	int start1 = 0;
	int end1 = start1+gap-1;
	int start2 = end1+1;
	int end2 = min(start2 + gap - 1,len - 1);     //When there are two merging segments
	while(start2 < len)//Sorting by loop instead of recursion
	{
		//When the two merging segments have not been compared
		while(start1 <= end1 && start2 <= end2)
		{
			if(arr[start1] <= arr[start2]) brr[i++] = arr[start1++];
			else brr[i++] = arr[start2++];
		}
		while(start1 <= end1)  brr[i++] = arr[start1++];
		while(start2 <= end2)  brr[i++] = arr[start2++];
		start1 = end2+1;
		end1 = start1+gap-1;
		start2 = end1+1;
		end2 = min(start2+gap-1,len-1);
	}
	while(start1 < len)  //If the second merge paragraph does not exist at the end, the number in the first merge paragraph is placed in brr []
		brr[i++] = arr[start1++];
	for(int i = 0;i < len;i++)    //Numeric copy
		arr[i] = brr[i];
}
void MergeSort(int *arr,int len)
{
	for(int i = 1;i < len;i *= 2)   //i denotes the number of groupings in the form of 1248....
	{
		Merge(arr,len,i);
	}
}
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;++i) cin>>a[i];
    MergeSort(a,n);
    for(int i=0;i<n;++i) printf("%d ",a[i]);
    puts("");
}

Linked list form

Merge sorting with linked lists is slightly different from array sorting, but the idea is the same. The only difficulty is how to find the middle point of the list. Here we need to use an additional skill - speed pointer. Quick and slow pointers are often used to judge whether there is a link in the list. Simply speaking, there are two pointers. The fast pointer walks two nodes at a time and the slow pointer walks one node at a time. When the fast pointer reaches the end of the list, the slow pointer reaches half of the list, which is the intermediate node we want.
The list code comes from: https://blog.csdn.net/jwwww/article/details/82056488.

Because linked lists are not as convenient as arrays, a recursive form is used here.

#include<bits/stdc++.h>
using namespace std;
//List structure unit
struct Node{
    int val;
    Node* next;
};
 
//node -- linked list header
Node* MergeSort(Node* node){
    //First, determine whether the length of the list is greater than 1, and no sorting is required when the length is less than 1.
    if(node!=NULL&&node->next!=NULL){
        //Find the middle node of the list by using the fast and slow pointer
        Node *fast=node->next;
        Node *slow=node;
        while(fast!=NULL&&fast->next!=NULL){
            fast=fast->next->next;
            slow=slow->next;
        }
 
        //Separate the linked list into two parts
        Node *p1=MergeSort(slow->next);
        slow->next=NULL;                 //It's important here. Think about why.
        Node *p2=MergeSort(node);
 
        //Merging two subchains
        Node *p0=(Node *)malloc(sizeof(Node));
        Node *p=p0;
        while(p1!=NULL&&p2!=NULL){
            if(p1->val<p2->val){
                p->next=p1;
                p1=p1->next;
            }else{
                p->next=p2;
                p2=p2->next;
            }
            p=p->next;
        }
 
        if(p1!=NULL){
            p->next=p1;
        }
 
        if(p2!=NULL){
            p->next=p2;
        }
 
        p=p0->next;
        free(p0);
        return p;
    }
    return node;
}
int main()
{
	
}

Merging Sort to Find Inverse Ordinal Number

Array plus recursive form

For example: A=1,4,6,7,9 B=2,3,5,10,13,21. In erge, it is found that the current element i is larger than 2, so the inverse number of 4 needs + 1, and because 6, 7 and 9 are behind 4, the inverse number of 6, 7 and 9 should also be + 1, so the total inverse number should be added last-i+1. (If the element i is smaller than B[j] (for example, 4 is smaller than 5), it is impossible to determine the change of the inverse number. No modification.
Code:

#include<iostream>
using namespace std;
int count=0;//Newly added
void Merge(int* A,int left,int mid,int right,int* C)
{	//Merge can arrange two ordered arrays with time complexity: o(n)
	int i=left;
	int j=mid+1;
	int k=left;
	while(i <= mid && j <= right)
	{
		if(A[i] <= A[j])
			C[k++]=A[i++];
		else
		{
			C[k++]=A[j++];
			count += mid-i+1;//Newly added
		}
	}
	while(i <= mid)
		C[k++]=A[i++];
	while(j <= right)
		C[k++]=A[j++];
	//C [] has been ordered to copy the data in C [] back to the original array A []
	for(int i=left;i <= right;++i)
		A[i]=C[i];
}	
void MergeSort(int* A,int left,int right,int* C)//Suppose MergeSort can sort a disorderly array A.
{
	if(left < right)
	{
		int mid=(left+right)/2;
		MergeSort(A,left,mid,C);//Arrange an array 1
		MergeSort(A,mid+1,right,C);//Arrange an array 2
		Merge(A,left,mid,right,C); //Merge two ordered arrays
	}
}
 
void main()
{
	int A[]={2,1,3,6,4,0,11,3,5};
	int len=sizeof(A)/sizeof(A[0]);
	int *C=new int[len];
	MergeSort(A,0,len-1,C);
	for(int i=0;i<len;++i)
		cout<<A[i]<<' ';
	cout<<endl;
	cout<<count<<endl;
	delete[] C;
}

 

Topics: less