Sorting-merge sort and counting sort


1. Merge sort

1. Concept

It is an effective and stable sorting algorithm based on the merge operation. This algorithm is a very typical application using the divide and conquer method (Divide and Conquer). Merge the already ordered subsequences to obtain a completely ordered sequence; that is, first make each subsequence orderly, and then make the subsequence segments orderly. If two ordered lists are merged into one ordered list, it is called a two-way merge.

Insert image description here

2. Process

Assumption:
Left half interval->ordered
Right half interval->ordered
How to sort left and right?
When there is only one element left, we can default to it being ordered, so we can use recursion to divide the elements in the array into one, and then merge the two groups into two groups, and so on.
Merge, compare the smaller ones in order and put them into the new temporary array. After completing the sorting, copy the data of the temporary array back to the original array
Process chart:
Insert image description here

3. Code implementation

recursion:

void Print(int* arr, int n) {
    
    

	for (int i = 0; i < n; i++)
		printf("%d ", arr[i]);
}
//递归


void _MergeSort(int *a,int *t,int left,int right) {
    
    
	//结束条件
	if (left >= right)
		return;

	int mid = (left + right) >> 1;//取中间数,划分区间
	//[left  mid]  [mid+1  right]
	//递归
	_MergeSort(a, t, left, mid);
	_MergeSort(a, t, mid + 1, right);
	//回归
	int begin1 = left, end1 = mid;//左区间
	int begin2 = mid + 1 , end2  = right;//右区间
	//临时数组下标->对应的是数组a的下标
	int index = left;
	//当左区间或者右区间,遍历完了就结束了
	while (begin1 <= end1 && begin2 <= end2) {
    
    
	//选择小的放进临时数组
		if (a[begin1] < a[begin2])
			t[index++] = a[begin1++];
		else
			t[index++] = a[begin2++];
	}
	//判断左右两边是否都空了,不为空将后面补上
	while (begin1 <= end1)
		t[index++] = a[begin1++];
	while (begin2 <= end2)
		t[index++] = a[begin2++];
		//最后拷贝回去
	for (int i = left; i <= right; ++i)
		a[i] = t[i];
 }
void MergeSort(int* a, int n) {
    
    
	int* t = (int*)malloc(sizeof(int) * n);
	_MergeSort(a, t, 0, n - 1);
	
	free(t);
}

int main() {
    
    
	int a[] = {
    
     3710962385 };
	MergeSort(a, sizeof(a) / sizeof(a[0]));
	Print(a, sizeof(a) / sizeof(a[0]));
	return 0;
}

Recursive graph (left, first recursive and then recursive):
Insert image description here

Non-recursive:
We implement non-recursion through loops
(1) Set a gap to divide the number of merges, first set gap=1 , in this way, the first time the control is to merge two numbers, the gap is multiplied by 2 to increment, and it ends when gap>n (array size)
(2) Two numbers may appear during the merging process. Situation
a. There is no element on the right during the merging process
such as:
Insert image description here
Solution: Because it has been arranged, just break it Just loop
b. There are elements on the right but not enough
such as:
Insert image description here
Solution: Make corrections and change the subscript on the right end Change to n-1 (array size-1)

Code:

//非递归

void MergeSortNonR(int* a, int* t,int n) {
    
    
	int gap= 1;//划分一次归并多少个元素
	//结束条件
	while (gap<n) {
    
    
		for (int i = 0; i < n; i += 2*gap) {
    
    
		//通过gap划分区间
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + gap * 2 - 1;
			//情况a,此时直接打破即可
			if (begin2 >= n)
				break;
				//情况b,进行纠正
			if (end2 >= n)
				end2 = n - 1;
 
			int index = i;//从控制的区间最小的位置开始
			//下面过程与递归过程一样
			while (begin1 <= end1 && begin2 <= end2) {
    
    
				if (a[begin1] < a[begin2])
					t[index++] = a[begin1++];
				else
					t[index++] = a[begin2++];
			}
			while (begin1 <= end1)
				t[index++] = a[begin1++];
			while (begin2 <= end2)
				t[index++] = a[begin2++];
			for (int j = i; j <= end2; j++)
				a[j] = t[j];
		}
		gap *= 2;//每次加倍
	}
}



void MergeSort(int* a, int n) {
    
    
	int* t = (int*)malloc(sizeof(int) * n);
	MergeSortNonR(a, t, n);
	free(t);
}

int main() {
    
    
	int a[] = {
    
     6,3,7,1,9,5,2,8,0,4 };
	MergeSort(a, sizeof(a) / sizeof(a[0]));
	Print(a, sizeof(a) / sizeof(a[0]));
	return 0;
}

4. Complexity

Time complexity:
(1) Loop part: N
(2) Recursive part: Because it is halved every time, it is logN ( Taking base 2)
So the time complexity is: O(N*logN)
Space complexity:
Because it is necessary Re-open an array, so the space complexity is O(N)

5. Stability

The order of the same elements will not change during the merging process, so it is stable.

2. Counting sorting

1. Ideas

Count the number of occurrences of each number through mapping, and then use the number of times to sort
For example:
Insert image description here
The above is to create a space with the maximum number Solution: Find the range , use range +1 to create temporary space For example:
But if we encounter a large number, we need to create space, which will be very wasteful

Insert image description here

2. Code implementation

//计数排序
void  CountSort(int* a, int n) {
    
    
	int max = a[0];
	int min = a[0];
	//求出数组的范围
	for (int i = 0; i < n; i++) {
    
    
		if (max < a[i])
			max = a[i];
		if (min > a[i])
			min = a[i];
	}
	int  t = max - min+1;
	//临时空间
	int* p = (int*)calloc(t,sizeof(int));
	//统计个数
	for (int j = 0; j < n; j++) {
    
    
		//a[j]-min当下标,我们下次直接加回min即可
		p[a[j] - min]++;
	}
	int i = 0;
	//按顺序拷贝回原来的数组
	for (int j = 0; j < t; j++) {
    
    
		
		while (p[j]) {
    
    
			a[i] = j + min;
			i++;
			p[j]--;
		}
	}
	free(p);
	p = NULL;
}

3. Complexity:

Space complexity: Because a temporary space needs to be created, the complexity is O(N);
Time complexity: O(N+t)

4. Stability

During the statistics and reordering process, the positions of the same elements may be exchanged, so it is unstable.

The above is what I shared. If there are any mistakes, please leave a message in the comment area.
Finally, thank you everyone for watching!

Guess you like

Origin blog.csdn.net/2302_79539362/article/details/134986382