Data structure - six sorts (insert, select, Hill, bubble, heap, quick sort)


1. Insertion sort

1.1 Basic ideas

Insert the records to be sorted into a sorted sequence one by one according to the size of their key values ​​until all records are inserted, and a new sequence is obtained 

The Landlord we are familiar with is an insertion sort

 1.2 Code implementation

Here we turn an unordered array into an ordered array

  1. Insertion sort time complexity analysis
  • Best case: the array to be sorted is ordered

Just compare the current number with the next number

A total of N- 1 comparisons are required

时间复杂度为 : O ( N )

  • Worst case: the array to be sorted is in reverse order

It is possible that the number after each move is moved backwards
The time complexity is: O(N^2)

as the picture shows:

 Here we need to define two variables, end and tmp, one pointing to the first element and one pointing to the following element

do not move when end<tmp (and vice versa)

Code display:

void InsertSort(int* a, int n)
{
	for (int i = 0; i < n - 1; ++i)
	{
		// [0, end] 有序,插入tmp依旧有序
		int end = i;
		int tmp = a[i + 1];

		while (end >= 0)
		{
			if (a[end] > tmp)
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}

		a[end + 1] = tmp;
	}
}

2. Selection sort

2.1 Basic idea

Select the smallest (or largest) element from the data elements to be sorted each time, and store it at the beginning of the sequence until all the data elements to be sorted are exhausted

Note here that some questions will be tested:

In the past, we selected a maximum or minimum for each pass.
After optimization: select two for one pass, and the largest and smallest
are placed on the left and right ends of the array respectively.

2.2 Code implementation

  1. Selection Sort Time Complexity Analysis

Regardless of whether the array is ordered or unordered, the selection
sort needs to traverse the array over and over again.
Even if we have made some optimizations here
, it still needs to go 2/N times, and then multiply by the number of times N

The time complexity is: O(N^2)

In order to show this more intuitively, we directly import a picture to illustrate

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		int maxi = begin, mini = begin;
		for (int i = begin; i <= end; i++)
		{
			if (a[i] > a[maxi])
			{
				maxi = i;
			}

			if (a[i] < a[mini])
			{
				mini = i;
			}
		}

		Swap(&a[begin], &a[mini]);
		// 如果maxi和begin重叠,修正一下即可
		if (begin == maxi)
		{
			maxi = mini;
		}

		Swap(&a[end], &a[maxi]);

		++begin;
		--end;
	}
}

3. Hill sort

3.1 Basic ideas:

  • Do optimization on direct insertion sort:
    1. 分组预排序,使数组接近有序
    2. 直接插入

时间复杂度的分析:

Generally, the time complexity of default Hill sorting is:

O ( N * log2 N) or
O (N * log3 N)

According to the data obtained from a large number of experiments, we finally set the complexity as:
time complexity range:

it can also be directly regarded as: n1.3

It can be seen from the figure that
the idea of ​​group prearrangement and insertion here is the same

3.2 Code implementation

//希尔排序
void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; i++)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

4. Heap sort

4.1 Basic idea

  1. 建立一个大堆(升序建大堆)
  2. 将堆顶元素与最后一个元素交换
  3. 交换后堆元素减一,重新调整堆

After one cycle, we put the maximum value in the array in the last position, and in the next cycle, put the second-to-last value in the second-to-last position, and so on until the array becomes ordered.

  1. Sort ascending - build a large pile
  2. Sort in descending order - build a small heap
  3. Left child: child = parent * 2 + 1
  4. Right child: child = parent * 2 + 2.
  5. parent = (child - 1) / 2

4.2 Code implementation

void AdjustDown(int* a, int n, int  parent)
{
	int child = parent * 2 + 1;
	//选出最大的孩子
	while (child < n)
	{
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		//最大的孩子和父亲比
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

//堆排序
void HeapSort(int* a, int n)
{
	//建堆--升序建大堆
	//向下调整建堆 --时间复杂度:O(n)
	for (int i = (n - 2) / 2; i >= 0; i--)
	{
		AdjustDown(a, n, i);
	}

	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, end, 0);
		end--;
	}
}

5. Quick Sort

5.1 Basic ideas

Quick sort recursive version 1 - hoare

important point:

  1. If you choose keyi on the left, go to the right first; if you choose keyi on the right, go to the left first
  2. Select the value smaller than a[keyi] on the right, and select the value larger than a[keyi] on the left
  3. Note the handling of boundaries in special cases.

5.1.2 Code implementation 

int GetMidnum(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] > a[mid])
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if(a[left] > a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
	//a[left] <= a[mid]
	else
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] < a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
}

int PartSort1(int* a, int left, int right)
{
	int keyi = left;
	int mid = GetMidnum(a, left, right);
	Swap(&a[mid], &a[keyi]);
	while (left < right)
	{
		while (left < right && a[right] >= a[keyi])
		{
			right--;
		}
		while (left < right && a[left] <= a[keyi])
		{
			left++;
		}
		Swap(&a[left], &a[right]);
	}
	Swap(&a[left], &a[keyi]);
	keyi = left;
	return keyi;

}

5.2 Quick sort recursive version 2 - pit digging method

5.2.1 Basic ideas

This is different from hoare in terms of understanding, and the idea of ​​digging holes is easier to understand. It is a question of which area to go first.

The implication is to dig a hole and stuff it in

 5.2.2 Code implementation

int GetMidnum(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] > a[mid])
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if(a[left] > a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
	//a[left] <= a[mid]
	else
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] < a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
}


int PartSort2(int* a, int left, int right)
{
	int mid = GetMidnum(a, left, right);
	Swap(&a[mid], &a[left]);
	int key = a[left];
	int hole = left;
	while (left < right)
	{
		while (left < right && a[right] >= key)
		{
			right--;
		}
		a[hole] = a[right];
		hole = right;
		while (left < right && a[left] <= key)
		{
			left++;
		}
		a[hole] = a[left];
		hole = left;
	}
	a[left] = key;
	return left;

}

5.3 Back and forth pointer method

5.3.1 Basic idea

  • Define two pointers cur and prev
  • cur points to the second element
  • prev points to the element before cur
  • c找比基准值小的值
  • 找到后停下,p向后走一格
  • 再交换c和p指向的值
  • Finally, after c walks through the array:
  • 交换key和prev的值

 5.3.2 Code implementation

int GetMidnum(int* a, int left, int right)
{
	int mid = (left + right) / 2;
	if (a[left] > a[mid])
	{
		if (a[mid] > a[right])
		{
			return mid;
		}
		else if(a[left] > a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
	//a[left] <= a[mid]
	else
	{
		if (a[mid] < a[right])
		{
			return mid;
		}
		else if (a[left] < a[right])
		{
			return right;
		}
		else
		{
			return left;
		}
	}
}


int PartSort3(int* a, int left, int right)
{
	int keyi = left;
	int prev = left;
	int cur = prev + 1;
	int mid = GetMidnum(a, left, right);
	Swap(&a[mid], &a[left]);
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && prev++ != cur)
		{
			Swap(&a[cur], &a[prev]);
		}
		cur++;
	}
	Swap(&a[prev], &a[keyi]);
	keyi = prev;
	return prev;
}

6. Merge sort

6.1 Basic ideas

  • To make the array as a whole orderly, the left half and the right half must be changed into order, and then a single merge and sort is performed to split the array into two parts A and B. To make the A array orderly, it is necessary to , A is also split into two parts, so that the left/right halves are ordered, and keep splitting until the array has only one element.

6.2 Code implementation

void MergeSortNonR(int* a, int n)
{
	int* tem = (int*)malloc(sizeof(int) * n);
	int begin = 0;
	int end = n - 1;
	int gap = 1;

	while (gap < n)
	{
		int j = 0;
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			//printf("修正前:[ %d , %d ] [ %d , %d ]\n",begin1,end1,begin2,end2);
			if (end1 >= n || begin2 >= n)
			{
				break;
			}
			if (end2 >= n)
			{
				end2 = n - 1;
			}
			//printf("修正后:[ %d , %d ] [ %d , %d ]\n", begin1, end1, begin2, end2);
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tem[j++] = a[begin1++];
				}
				else
				{
					tem[j++] = a[begin2++];
				}
			}

			while (begin1 <= end1)
			{
				tem[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tem[j++] = a[begin2++];
			}
			memmove(a + i, tem + i, sizeof(int) * (end2 - i + 1));
			
		}
		gap *= 2;
	}
}

Merge sort non-recursive version 2 (implementation of the overall merge idea)

//归并排序 -- 非递归版2
void MergeSortNonR2(int* a, int n)
{
	int* tem = (int*)malloc(sizeof(int) * n);
	int begin = 0;
	int end = n - 1;
	int gap = 1;

	while (gap < n)
	{
		int j = 0;
		for (int i = 0; i < n; i += 2 * gap)
		{
			int begin1 = i, end1 = i + gap - 1;
			int begin2 = i + gap, end2 = i + 2 * gap - 1;
			//printf("修正前:[ %d , %d ] [ %d , %d ]\n",begin1,end1,begin2,end2);
			if (end1 >= n)
			{
				end1 = n - 1;
				begin2 = n;
				end2 = n - 1;
			}
			else if(begin2 >= n)
			{
				begin2 = n;
				end2 = n - 1;
			}
			else if(end2 >= n)
			{
				end2 = n - 1;
			}
			//printf("修正后:[ %d , %d ] [ %d , %d ]\n", begin1, end1, begin2, end2);
			while (begin1 <= end1 && begin2 <= end2)
			{
				if (a[begin1] < a[begin2])
				{
					tem[j++] = a[begin1++];
				}
				else
				{
					tem[j++] = a[begin2++];
				}
			}

			while (begin1 <= end1)
			{
				tem[j++] = a[begin1++];
			}
			while (begin2 <= end2)
			{
				tem[j++] = a[begin2++];
			}
		}
		memmove(a, tem, sizeof(int) * n);
		gap *= 2;
	}
}

The above are the six major rankings we talked about today, thank you for your favorites and likes, see you next time


Guess you like

Origin blog.csdn.net/m0_74459304/article/details/131749022