数据结构––排序

前面,我们已经学习了数据结构中的各种知识

那么接下来,我们学习排序。之前我们了解过一些排序,其中最熟悉的就是冒泡排序了。

在日常生活中,排序无处不在

一.直接插入排序

是最简单的排序方法,将一条数据插入到已经排好的有序表中,从而得到一个新的,数据量增加1的有序表

最好从后往前比

1.图示

1.先看第一个数,将数组划分为有序部分和无序部分

看第一个数2,一个数一定是有序的,所以将2划分为有序,后面都是无序

2.无序部分的首个插入到有序部分

取出无序部分的首个,在有序部分从后向前比较,插入到合适的位置

3.重复第二步直到无序部分全部插入有序

8需要比较一次

3要比较多次,注意是多次比较,直接插入,不是比较一次插入一次(与冒泡排序不同)

后面一直比较,插入,重复直到无序部分全部到有序

2.代码实现

从上面的图示中可以看出来,这个算法是遍历一遍所有数然后分别插入,第一个数是有序的,不要排,所以需要n-1次遍历

#include<bits/stdc++.h>

using namespace std;

void InsertSort(int a[],int l)
{
    int temp;
    int j;
    for(int i=1;i<l;i++)
    {
        if(a[i]<a[i-1])
        {
            temp=a[i];
            for(j=i-1;j>=0&&temp<a[j];j--)
            {
                a[j+1]=a[j];
            }
            a[j+1]=temp;

        }
        for(int k=0;k<l;k++)
            cout<<a[k]<<" ";
        cout<<endl;

    }
}


int main()
{
    int a[10]={2,5,8,3,6,9,1,4,7};
    int b[10]={1,2,3,4,5,6,7,8,9};
    int len=9;
    InsertSort(a,len);
    return 0;
}

时间复杂度(最坏)O(N^2)--逆序

时间复杂度(最好)O(N)--顺序

与冒泡排序相比,插入更好

二分查找和冒泡排序-CSDN博客

冒泡排序的实现

void BubbleSort(int* a, int n)
{
	for (int j = 0; j < n; ++j)
	{
		bool exchange = false;
		for (int i = 1; i < n-j; i++)
		{
			if (a[i - 1] > a[i])
			{
				int tmp = a[i];
				a[i] = a[i - 1];
				a[i - 1] = tmp;

				exchange = true;
			}
		}

		if (exchange == false)
		{
			break;
		}
	}
}

二.希尔排序

1.预排序(接近有序)

2.插入排序

间隔为gap分为一组,总计gap组

预排序:对gap组数据分别(插入)排序

上图中,9,6,3,0是一组;8,5,2是一组;7,5,1是一组;那么结果就是

也就是0 2 1 3 5 7 6 8 4 9,达到了预排序的效果--接近有序

void ShellSort(int* a, int n)
{
	// 1、gap > 1 预排序
	// 2、gap == 1 直接插入排序

	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;  // +1可以保证最后一次一定是1
		// gap = gap / 2;
		for (int i = 0; i < n - gap; ++i)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}

			a[end + gap] = tmp;
		}
	}
}

gap越大,跳的越快,越不接近有序(gap=1有序)--大大的数可以更快的到后面,小的数越快到前面

gap越小,大的小的挪动越慢,越接近有序

gap==1是插入排序

gap没有规定的数,但是通常n/3+1(保证最后是1)比较合适

时间复杂度:O(N)

三.选择排序

从待排序的数据中选出最小的和最大的,然后最小的往前放,最大的往后放,重复执行,直到待排数据全部完成。

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;
	}
}

四.堆排序

调整

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 = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

升序--大堆

/ 排升序
void HeapSort(int* a, int n)
{
	// 建大堆
	for (int i = (n-1-1)/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;
	}
}

五.冒泡排序

void BubbleSort(int* a, int n)
{
	for (int j = 0; j < n; ++j)
	{
		bool exchange = false;
		for (int i = 1; i < n-j; i++)
		{
			if (a[i - 1] > a[i])
			{
				int tmp = a[i];
				a[i] = a[i - 1];
				a[i - 1] = tmp;

				exchange = true;
			}
		}

		if (exchange == false)
		{
			break;
		}
	}
}

六.快速排序

在待排元素序列中任取一个元素作为基准值,按照该排序码将待排集合分割成两个子序列,左子序中的元素均小于基准值,右边的元素均大于基准值,左右子序列重复该工程

// hoare
// [left, right]
int PartSort1(int* a, int left, int right)
{
	int keyi = left;
	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[keyi], &a[left]);

	return left;
}

挖坑法

// 挖坑法
// [left, right]
int PartSort2(int* a, int left, int right)
{
	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[hole] = key;

	return hole;
}

前后指针法

// 前后指针法
// [left, right]
int PartSort3(int* a, int left, int right)
{
	int prev = left;
	int cur = left+1;
	int keyi = left;
	while (cur <= right)
	{
		if (a[cur] < a[keyi] && ++prev != cur)
		{
			Swap(&a[prev], &a[cur]);
		}

		++cur;
	}

	Swap(&a[prev], &a[keyi]);
	keyi = prev;
	return keyi;
}

void QuickSort(int* a, int begin, int end)
{
	if (begin >= end)
		return;

	int keyi = PartSort3(a, begin, end);
	// [begin, keyi-1] keyi [keyi+1, end]

	QuickSort(a, begin, keyi - 1);
	QuickSort(a, keyi+1, end);
}

七.归并排序

void _MergeSort(int* a, int begin, int end, int* tmp)
{
	if (begin == end)
		return;

	int mid = (begin + end) / 2;
	// [begin, mid] [mid+1, end]
	_MergeSort(a, begin, mid, tmp);
	_MergeSort(a, mid+1, end, tmp);

	// 归并两个区间
	// ...

	int begin1 = begin, end1 = mid;
	int begin2 = mid+1, end2 = end;
	int i = begin;
	while (begin1 <= end1 && begin2 <= end2)
	{
		if (a[begin1] < a[begin2])
		{
			tmp[i++] = a[begin1++];
		}
		else
		{
			tmp[i++] = a[begin2++];
		}
	}

	while (begin1 <= end1)
	{
		tmp[i++] = a[begin1++];
	}

	while (begin2 <= end2)
	{
		tmp[i++] = a[begin2++];
	}

	memcpy(a+begin, tmp+begin, sizeof(int) * (end - begin + 1));
}
相关推荐
小字节,大梦想21 分钟前
【C++】二叉搜索树
数据结构·c++
我是哈哈hh42 分钟前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
丶Darling.1 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo5202 小时前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法
Indigo_code2 小时前
【数据结构】【链表代码】合并有序链表
数据结构·windows·链表
jiyisuifeng19912 小时前
代码随想录训练营第54天|单调栈+双指针
数据结构·算法
我言秋日胜春朝★2 小时前
【C++】红黑树
数据结构
新晓·故知2 小时前
<基于递归实现线索二叉树的构造及遍历算法探讨>
数据结构·经验分享·笔记·算法·链表
gorgor在码农3 小时前
Mysql 索引底层数据结构和算法
数据结构·数据库·mysql
武昌库里写JAVA4 小时前
【Java】Java面试题笔试
c语言·开发语言·数据结构·算法·二维数组