Algorithms and Data Structures (3)

pile

1. The heap structure is a complete binary tree structure implemented with an array.
The subscript of the left child of the root node is: 2 i+1, and the subscript of the right child is 2 i+2. The parent node of the two children is (i-1)/2 rounded down to 2.
In a complete binary tree, if the maximum value of each subtree is at the top, it is a large root pile.
Compare the child with the parent node from bottom to top. If the child leaf If the value of the node is greater than the root node, then swap, otherwise, stop the upward comparison
3, in the complete binary tree, if the minimum value of each subtree is at the top, the small root heap is
opposite to the big root heap
4, the heapInsert and heapify of the heap structure operate
on the big root The comparison between the heap and the small root heap is the process of heapInsert;
the code demonstration of the large root heap heapInsert:

void heapify(vector<int> &a, int index)
{
    
    
	while (a[index] > a[(index - 1) / 2])
	{
    
    
		//两个元素互换
		swap(a, a[index], a[(index - 1) / 2]);
		//向上反馈
		index = (index - 1) / 2;
	}
}

Heapify operation:
here is an example, when the user wants to delete the maximum value in the large root heap, we first need to overwrite the last number in the array to the 0 position in the array, and then the root node starts to compare with the minimum value of the two cotyledon nodes Swap, and then compare and swap the replaced root node with the two cotyledon nodes at the current position after being swapped.

void heapify(vector<int> &a, int index, int heapsize)
{
    
    
	//index表示从何位置开始进行heapify操作操作
	//heapsize表示数组的长度
	//设置左孩子的下标
	int left = index*2+1;
	//如果当前根节点还有叶节点,则操作
	while(left < heapsize)
	{
    
    
		//两个孩子中,谁的值大,则把下标给largest
		int largest = left + 1 < heapsize && a[left+1] > a[left]? left+1 : left;
		//父和孩子之间的最大值谁最大,将下标给largest
		largest = a[largest] > a[index] ? largest :index;
		
		//如果最大值就是根节点,则退出
		if(largest == index)
			break;
		
		//否则则交换
		swap(a, index, largest);
		index = largest;
		left = index*2+1;
	}
}

2. Heap sort

Ideas:
1. Arrange the array into a heap structure, and form a big root heap through the heapInsert operation
2. Exchange the node at position 0 of the big root heap with the last node, decrease the heapsize by 1, and put the last element in the heap into 0 position, perform heapify operation
3. Repeat step 2 until the size of the heap is 0, and the end operation
animation shows:
Please add a picture description

Code:

void heapify(vector<int>&a, int index1, int heapsize)
{
    
    

	//进行heapifty
	//设置左孩子的节点
	int left = 2 * index1 + 1;

	//如果有左孩子,则开始进行heapifty
	while (left < heapsize)
	{
    
    

		//如果有右孩子,且右孩子的数值较大,则将右孩子的下标设置为largest
		int largest = left + 1 < heapsize && a[left + 1] > a[left] ? left + 1 : left;

		//比较根节点与较大孩子的数值,如果根节点大,则跳出循环
		if (index1 == largest)
		{
    
    
			break;
		}

		//否则互换
		swap(a, index1, largest);

		//设置将最大值的下标赋值给index1,继续向下
		index1 = largest;
		left = 2 * index1 + 1;
	}
}

void heapInsert(vector<int> &a, int index)
{
    
    
	while (a[index] > a[(index - 1) / 2])
	{
    
    
		//两个元素互换
		swap(a, a[index], a[(index - 1) / 2]);

		//向上反馈
		index = (index - 1) / 2;
	}
}

void heapSort(vector<int> &a, int heapsize)
{
    
    

	if (a.size() < 2)
		return;

	//将数组构建成大根堆
	for (int i = heapsize-1; i >= 0; i--)
	{
    
    
		heapify(a, i, heapsize);
	}

	swap(a, 0, --heapsize);
	while (heapsize>0)
	{
    
    
		//将变成大根堆的根节点与数组的最后一个数互换,并且将heapsize减小1
		heapify(a, 0, heapsize);
		swap(a, 0, --heapsize);
	}	
}

3. Heap sort extension

An almost ordered array is known. Almost ordered means that if the array is arranged in order, each element can move no more than k, and k is relatively small compared to the array. Please choose an appropriate sorting algorithm to sort this data.
We first build a small root heap with k elements, because the maximum moving distance is k, so in extreme cases, use this method to put the root node of the small root heap, that is, the minimum value at 0, and then point to Then move one position, and then put the element k in the array below into the small root heap to form a small root heap again, and so on. Finally, pop up the numbers in the small root heap from small to large.
In C++, the bottom layer of the multiset operation is the structure of the binary tree.

void SortArrayDistanceLessK(vector<int> &a, int k)
{
    
    
	//定义一个multiset容器
	multiset<int> s;

	//设置遍历的起始点
	int index = 0;

	//防止k超过数组长度,要限制传入multiset容器的元素数量
	int c = a.size();
	int b = min(c, k);
	for (; index <= b; index++)
	{
    
    
		//将数组的前K个数依次传到multiset容器中
		s.insert(a[index]);
	}

	int i = 0;
	//依次将K后面的元素传入multiset容器中,并弹出第一个元素
	for (; index < a.size(); index++)
	{
    
    
		//将k之后的元素一个一个压入到multiset中
		s.insert(a[index]);

		//将set的第一个元素放到数组的第一个位置,并将multiset容器第一个元素删除
		set<int>::const_iterator it = s.begin();
		a[i] = *it;

		//删除第一个元素
		s.erase(s.begin());
		i++;
	}

	//将multiset容器中的数据以此弹出
	while (!s.empty())
	{
    
    
		//将set的第一个元素放到数组的第一个位置,并将multiset容器第一个元素删除
		set<int>::const_iterator it = s.begin();
		a[i++] = *it;

		//删除第一个元素
		s.erase(s.begin());
	}
}

4. Bucket Sort

Radix sort:
c++ code example

#include <cmath>

int getDigit(int x, int d)
{
    
    
	//返回所需位数的数值
	return((x / (int)pow(10, d - 1)) % 10);
}

//桶排序
void radixSort(vector<int> &a, int L, int R, int digit)
//L:要排序的左区域
//R:要排序的右区域
//digit十进制的位数
{
    
    
	 //以十为基底
	int radix = 10;
	int i = 0, j = 0;

	//设置辅助空间,其大小与数组大小一致
	int *bucket = new int[R - L + 1];

	//有多少位就进出桶多少次,开始入桶
	for (int d = 1; d <= digit; d++)
	{
    
    
		//count[0]为当前位(d位)是0的数字有多少个
		//count[1]为当前位(d位)是0-1的数字有多少个
		//count[2]为当前位(d位)是0-2的数字有多少个
		//count[i]为当前位(d位)是0-i的数字有多少个
		//申请一个辅助数组,记录上面的数据
		int *count = new int[radix];

		//将申请的内存全部附初值0
		for (int i = 0; i < radix; i++)
		{
    
    
			count[i] = 0;		
		}

		//开始入桶操作
		for (i = L; i <=R; i++)
		{
    
    
			j = getDigit(a[i], d);
			count[j]++;
		}

		//对辅助数组处理成前缀和
		for (i = 1; i < radix; i++)
		{
    
    
			count[i] = count[i] + count[i - 1];
		}

		//开始出桶操作
		for (i = R; i >= L; i--)
		{
    
    
			j = getDigit(a[i], d);
			bucket[count[j] - 1] = a[i];	
			count[j]--;
		}

		int j = 0;
		for (i = L; i <= R; i++)
		{
    
    
			a[i] = bucket[j];
			j++;
		}
	}
}

int maxbits(vector<int> &a)
{
    
    
	//定义一个最大数值暂存变量
	int largest = 0;
	for (int i = 0; i < a.size(); i++)
	{
    
    
		largest = max(largest, a[i]);
	}

	//开始计算最大数值的十进制数一共有多少位
	int res = 0;
	while (largest != 0)
	{
    
    
		res++;
		largest /= 10;
	}
	return res;
}


void radixSort(vector<int> &a)
{
    
    
	if (a.size() < 2)
		return;
	radixSort(a, 0, a.size() - 1, maxbits(a));

}

5. The stability and summary of the sorting algorithm

Between individuals of the same value, if the relative order does not change due to the sorting, the sorting is stable; otherwise, it is not.
Sorting without stability:
selection sorting, quick sorting, heap sorting
sorting with stability:
bubble sorting, insertion sorting, merge sorting, sorting under the idea of ​​​​every bucket sorting
has not been found so far Time complexity O(N*logN) , extra space complexity 0(1), and stable sorting.
insert image description hereNotice!
1. The additional space complexity of merge sort can be O(1), but it is very difficult and does not need to be mastered. If you are interested, you can search for "merge sort internal cache method".

2. "In-place merge sorting" will make the time complexity of merge sorting become o(N^2
) 3. Quick sorting can solve stability problems, but it is very difficult and you don't need to master it. You can search for "01stable sort"
4 , all improvements are not important, because there is no time complexity 0(N*logN), extra space complexity 0(1), and stable sorting.
5. There is a question that places odd numbers on the left side of the array and even numbers on the right side of the array, and requires the original relative order to remain unchanged. It is very difficult to encounter this problem.

Guess you like

Origin blog.csdn.net/qq_52302919/article/details/131037538