C++ I don't know the counting of the counting sorting algorithm of the algorithm series

1 Introduction

计数排序It is a relatively simple sorting algorithm, which 基本思想uses the principle of ordering the index numbers of the array.

For example, 原始数组sort the data (elements) in the following:

//原始数组
int nums[5]={9,1,7,6,8};

The basic idea used 计数排序is as follows:

  • Create one 排序数组. The size of the array is determined by the maximum value of the original array. If the maximum value of the original array is 9, then the length of the sorted array is 9+1. Why the length of the sorted array needs to be set in this way will be explained later.
int sortNums[10]={0}; //初始化值为 0
  • Read the value of the original array 数据as the number of occurrences of this data as the sorted array .数据排序数组索引号

    This also explains why the length of the sorted array must be the maximum value in the original array plus 1. Because 排序数组it must be possible to provide an index number for the original array 最大值.

1.png

  • Then 排序数组the value in the output is not 0the index number.

2.png

Encoding implementation:

#include <iostream>
using namespace std;
int main(int argc, char** argv) {
	//原数组
	int nums[5]= {9,1,7,6,8};
	//排序数组
	int sort[10]= {0};
	//转存
	for(int  i=0; i<5; i++) {
		sort[nums[i]]++;
	}
	//输出排序数组
	for(int i=0; i<10; i++) {
		if(sort[i]!=0)
			cout<<i<<"\t";
	}
	return 0;
}

Output result:

3.png

From the brief description above, we can see that:

  • The time complexity of counting sort is O(n), and the time complexity is still considerable.
  • But so is space complexity O(n). Compared with sorting algorithms such as bubbling, selection..., the counting sorting algorithm trades space for time.

2. Two questions

2.1 The length of the sorted array

Counting sort uses the order of the array index numbers to sort the data, so it is necessary to map the original unordered array 数据to the index number of the sorted array. Therefore, there will be a minimum value constraint on the length of the sorted array, which is at least equal to the maximum value in the unordered array plus one.

Like the following unordered array:

int num[]={500,420,550};

In order to ensure that the data in the unordered array can be mapped to the corresponding index number, the length of the sorted array should be at least 551.

int sort[551]={0};

However, there are only 3one data that needs to be mapped, which will lead to a huge waste of space in the sorted array, which is also the disadvantage of counting sorting.

As shown below:

4.png

How to solve this problem?

You can create a sorted array by:

  • (max)Find the maximum and minimum values ​​in the original unsorted array (min). As above, the maximum value of the unordered array is 550, and the minimum value is 420.

  • The length of the specified sorting array is: max-min+1, that is, the length of the sorting array is: 131.

    int sort[131]={0}; //初始值为0
    
  • Mapping rules from unordered array to sorted array: 排序数组中的索引号=无序数组中的数据-最小值.

    Conversely, when traversing the sorted array: 无序数组中的数据=排序数组中的索引号+最小值.

5.png

Encoding implementation:

#include <iostream>
using namespace std;
int main(int argc, char** argv) {
	//原数组
	int nums[3]= {500,420,550};
	//硬代码求长度 
	int len=550-420+1; 
	//排序数组
	int sort[len]= {0};
	//转存
	for(int  i=0; i<3; i++) {
		sort[nums[i]-420 ]++;
	}
	//输出排序数组
	for(int i=0; i<len; i++) {
		if(sort[i]!=0)
			cout<<(i+420)<<"\t";
	}
	return 0;
}

Output result:

6.png

2.2 Duplicate questions

If there is duplicate data in the unordered array, according to the mapping principle of the counting sort algorithm, obviously, the same data will be mapped to the same position in the sorted array. A sorted array counts the same data through a counter scheme. This is also the origin of the name of the counting sort algorithm.

As shown in the figure below: and in 2the unordered array are mapped to the same position in the sorted array, and the value of the sorted array records the number of repeated data.129

7.png

Encoding implementation:

#include <iostream>
using namespace std;
int main(int argc, char** argv) {
	//原数组
	int nums[5]= {9,1,7,1,9};
	//排序数组
	int sort[10]= {0};
	//转存
	for(int  i=0; i<5; i++) {
		sort[nums[i] ]++;
	}
	//输出排序数组
	for(int i=0; i<10; ) {
		if(sort[i]!=0) {
			cout<<i<<"\t";
			sort[i]--;
		}else{
             i++;
        }
	}
	return 0;
}

Output result:

8.png

Here, only the repeated data can be counted, but the original sequence of the repeated data cannot be known. Therefore, in theory, the counting sort algorithm is unstable.

Is there a solution to preserve the original sequence of repeated data when outputting?

The answer is: transform the values ​​in the sorted array. The mapping position in the array no longer stores the number of data corresponding to this index number, but stores the number of all data before this index number.

9.png

The original unordered array is then traversed in reverse. Use its value as the index number of the sorted array, find out the value stored in the sorted array and then subtract one, and you will know which number the data should be in the sorted position.

10.png

Why reverse traversal?

The reason is very simple. When mapping, it is a forward traversal, so the first 1one in the unordered array 9must first be mapped to the position with the index number of the sorted array 9, and the last one 9must be mapped to the 9position with the index number of the sorted array. When taking it out, it should follow the first-in-last-out principle.

Encoding implementation:

#include <iostream>
using namespace std;
int main(int argc, char** argv) {
	//原数组
	int nums[5]= {9,1,7,1,9};
	//排序数组
	int sort[10]= {0};
	//映射
	for(int  i=0; i<5; i++) {
		sort[nums[i] ]++;
	}
	//转值,排序数组中存储此索引号及之前已经映射的数据个数
	for(int i=1; i<10; i++) {
		sort[i]+=sort[i-1];
	}
	//结果数组
	int res[5]= {0};
	//逆向遍历原无序数组
	for(int i=4; i>=0; i-- ) {
         //无序数组中的数据作为排序数组的索引号,其值减一,即为 nums[i]的正确位置
		res[--sort[nums[i]]]=nums[i];	
	}
	//输出结果
	for(int i=0;i<5;i++){
		cout<<res[i]<<"\t";
	} 
	return 0;
}

Output result:

11.png

3. Complete code and application

3.1 Complete code

The implementation process of counting and sorting is explained step by step above, and the basic ideas and solutions to problems are synthesized. Below is the complete code.

#include <iostream>
using namespace std;
/*
*查找数组中的最大值、最小值
*/
pair<int,int> getMaxAndMin(int nums[],int size) {
	int mixn=nums[0];
	int maxn=nums[0];
	for(int i=1; i<size; i++) {
		if(nums[i]>maxn)
			maxn=nums[i];
		if(nums[i]<mixn)
			mixn=nums[i];
	}
	pair<int,int> p(mixn,maxn);
	return p;
}
/*
*计数排序
*/
void jsSort(int nums[],int size,int res[]) {
	pair<int,int> p=getMaxAndMin(nums,size);
	int mx=p.second;
	int mi=p.first;
	int sortLen=mx-mi+1;
	//排序数组
	int sort[ sortLen ]= {0};
	//映射且计数
	for(int i=0; i<size; i++) {
		sort[nums[i]-mi]++;
	}
	//计总数
	for(int i=1; i<sortLen; i++) {
		sort[i]+=sort[i-1];
	}
	//逆向遍历原数组
	int idx=0;
	for(int i=size-1; i>=0; i--) {
		//有序位置 
		idx= --sort[nums[i]-mi];
		res[idx]=nums[i];
	}
}
int main(int argc, char** argv) {
	int nums[5]= {9,1,7,1,9};
	int size=sizeof(nums)/4;
	//结果数组
	int res[size]= {0};
	jsSort(nums,size,res);
	for(int i=0; i<5; i++) {
		cout<<res[i]<<"\t";
	}
	return 0;
}

3.2 Application

2019-10-19CSP-JThere is a procedural question related to the counting and sorting algorithm in the test paper .

Title description:

(Counting sort) Counting sort is a widely used sorting method. The following program uses double keyword counting nto 10000the integers within , from small to large.
For example, if there are three pairs of integers (3,4)、(2,4)、(3.3), it should be after sorting (2,4)、(3,3)、(3,4).
Enter the first line n, the next nline, and the iline 1 has two sums , representing the first keyword and the second keyword of the th pair of integers. Output after sorting from smallest to largest. data range . Tip: The second keyword should be sorted first, and then the first keyword. The array stores the result of sorting by the second key, and the array stores the result of sorting by double key.a[i]b[i]i
1≤n≤10^7,1≤a[i],b[i]≤10^4
ord[]res[]

Try to complete the program:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=10000000;
const int maxs=10000;
int n;
unsigned a[maxn],b[maxn],res[maxn],ord[maxn];
unsigned cnt[maxs+1];
int main() {
	scanf("%d",&n);
	for(int i=0; i<n; ++i) {
		scanf("%d%d",&a[i],&b[i]);
	}
	memset(cnt,0,sizeof(cnt));
	for(int i=0; i<n; ++i)
		1 ; //使用 cnt 数据计数 
	for(int i=0; i<maxs; ++i) 
		cnt[i+1]+=cnt[i];
	for(int i=0; i<n; ++i) 
		 2 ;
	memset(cnt,0,sizeof(cnt));
	for(int i=0; i<n; i++) 
		 3 ;
	for(int i=0; i<maxs; ++i) 
		cnt[i+1]+=cnt[i];
	for(int i=n-1; i>=0; --i)
		  4 ;
	for(int i=0; i<n; ++i)
		printf("%d %d\n",  5 );
	return 0;
}
  1. ① should be filled in ( B)

A、 ++cnt[i]

B、 ++cnt[b[i]]

C、 ++cnt[a[i] * maxs + b[i]]

D、 ++cnt[a[i]]

2) ② should be filled in ( D)

A、 ord[--cnt[a[i]]] = i

B、ord[--cnt[b[i]]] = a[i]

C、ord[--cnt[a[i]]] = b[i]

D、 ord[--cnt[b[i]]] = i

3) ③ should be filled in ( C)

A. ++cnt[b[i]]

B. ``++cnt[a[i] * maxs + b[i]]`

C. ++cnt[a[i]]

D. ++cnt [i]

4) ④ should be filled in ( A)

A、 res[--cnt[a[ord[i]]]] = ord[i]

B、 res[--cnt[b[ord[i]]]] = ord[i]

C、 res[--cnt[b[i]]] = ord[i]

D、 res[--cnt[a[i]]] = ord[i]

5) ⑤ should be filled in ( B)

A、a[i], b[i]

B、a[res[i]], b[res[i]]

C、a[ord[res[i]]] , b[ord[res[i]]]

D、a[res[ord[i]]] , b[res[ord[i]]]

4. Summary

Counting sort, bucket sort, and radix sort are similar sorting algorithms. Compared with the uncontrollable vertical length of the array in the counting sort, the radix sort uses a two-dimensional array to sort the data, and the size of the array is limited to between, and the 10X10space size is controllable. However, counting sort is better in terms of time complexity.

Guess you like

Origin blog.csdn.net/y6123236/article/details/131393324