数据结构 排序(直接插入排序、起泡(冒泡)排序、简单选择排序、快速排序、堆排序、基数排序)


需要用到的结构的定义

template<typename KeyType, typename InfoType>
struct RedType
{
	KeyType key;
	InfoType otherinfo;
};

enum Status { ERROR = 0, OK = 1 };

template<typename ElemType>
struct SqList
{
	ElemType data[MAX_LIST_SIZE + 1];
	int length;
};

template<typename KeyType, typename InfoType>
using HeapType = SqList<RedType<KeyType, InfoType>>;

template<typename KeysType, typename InfoType>
struct SLCell
{
	KeysType keys[MAX_NUM_OF_KEY];
	InfoType otheritems;
	int next;
};

template<typename KeysType, typename InfoType>
struct SLList
{
	SLCell<KeysType, InfoType>* r;
	int keynum, recnum;
};

using ArrType = int[RADIX];

直接插入排序

将数据分为两个部分,前面是已排好序的部分,后面是未排好序的部分。开始时假设第一个元素是已排好序的,之后每一轮都将未排好序的部分的第一个元素,与已排好序的部分的每一个元素,从后往前依次比较,不符合要求的元素就向后移一个位置,直到找到正确的位置。
时间复杂度(平均):O(n^2)
时间复杂度(最坏):O(n^2)
空间复杂度:O(1)
稳定性:稳定

template<typename KeyType,typename InfoType>
void insertSort(SqList<RedType<KeyType, InfoType>>& L)//直接插入排序
{
	for (int i = 2; i <= L.length; i++)
	{
		if (L.data[i].key < L.data[i - 1].key)
		{
			L.data[0] = L.data[i];//哨兵节点用来记录本轮数据
			L.data[i] = L.data[i - 1];
			int j;
			for (j = i - 2; L.data[0].key < L.data[j].key; j--)
				L.data[j + 1] = L.data[j];
			L.data[j + 1] = L.data[0];
		}
	}
}

起泡排序(冒泡排序)

每一趟从头到尾依次将相邻的两个元素进行比较,并根据要求交换位置,每一趟排序都可以确定一个元素到最后一个位置,直到所有元素都确定完成。同时,如果某一趟没有发生交换,则可以认为已经排好序了,此时无需继续排序,所以可以设置一个标志位,用于标志本轮是否发生交换,若未发生交换则可以直接退出排序。
时间复杂度(平均):O(n^2)
时间复杂度(最坏):O(n^2)
空间复杂度:O(1)
稳定性:稳定

template<typename KeyType, typename InfoType>
void bubbleSort(SqList<RedType<KeyType, InfoType>>& L)//起泡排序
{
	bool exchange = true;//标志本轮是否发生交换
	for (int i = 0; i < L.length && exchange; i++)//没发生交换可以直接退出
	{
		exchange = false;//默认没交换
		for (int j = 1; j < L.length - i; j++)
		{
			if (L.data[j].key > L.data[j + 1].key)
			{
				exchange = true;//发生交换
				RedType<KeyType, InfoType> t;
				t = L.data[j];
				L.data[j] = L.data[j + 1];
				L.data[j + 1] = t;
			}
		}
	}
}

简单选择排序

将数据分为两个部分,前面是已排好序的部分,后面是未排好序的部分。从头开始,每一次遍历未排好序的部分的所有元素,选择其中最小的元素,将其放到已排好序的部分的最后。
时间复杂度(平均):O(n^2)
时间复杂度(最坏):O(n^2)
空间复杂度:O(1)
稳定性:稳定

template<typename KeyType, typename InfoType>
int selectMinKey(SqList<RedType<KeyType, InfoType>>& L, int i)//选择从i开始到最后的最小关键字
{
	int min = i;
	for (int j = i + 1; j <= L.length; j++)
		if (L.data[j].key < L.data[min].key)
			min = j;
	return min;
}

template<typename KeyType, typename InfoType>
void selectSort(SqList<RedType<KeyType, InfoType>>& L)//简单选择排序
{
	for (int i = 1; i < L.length; i++)//从头开始遍历
	{
		int min = selectMinKey(L, i);//寻找最小关键字
		if (min != i)
		{//交换i与最小关键字的元素
			RedType<KeyType, InfoType> t;
			t = L.data[min];
			L.data[min] = L.data[i];
			L.data[i] = t;
		}
	}
}

快速排序

先确定一个枢轴,将所有数据分为两个部分,左边的比枢轴小,右边的比枢轴大,然后再对左右两个部分同样进行快速排序,直到序列有序。首先选择第一个元素作为枢轴,然后从最后一个元素开始向前,依次将每一个元素与枢轴进行比较,如果比枢轴小,则将该元素覆盖第一个元素,再从第一个元素向后,依次将每一个元素与枢轴进行比较,如果比第一个元素大,则将该元素覆盖上一步确定的元素,然后再从被覆盖的元素开始向前进行搜索与覆盖。以此类推,每一次都将不符合要求的元素覆盖另一边的元素,然后从另一边被覆盖的元素继续向前或向后搜索,直到两边相遇,相遇的位置再由枢轴覆盖,至此完成了一趟快速排序,然后继续对枢轴左右两边分别同样进行快速排序。
时间复杂度(平均):O(n log⁡n)
时间复杂度(最坏):O(n^2)
空间复杂度:O(log⁡n)
稳定性:不稳定

template<typename KeyType, typename InfoType>
int partition(SqList<RedType<KeyType, InfoType>>& L, int i, int j)//调整元素关于枢轴的位置并返回枢轴坐标
{
	L.data[0] = L.data[i];//哨兵节点记录枢轴数据
	KeyType pivotKey = L.data[i].key;//取最左边为枢轴
	while (i < j)//从左右向中间扫描
	{
		while (i < j && L.data[j].key >= pivotKey)//因为取最左边为枢轴,所以要从最右边开始
			j--;
		L.data[i] = L.data[j];
		while (i < j && L.data[i].key <= pivotKey)
			i++;
		L.data[j] = L.data[i];
	}
	L.data[i] = L.data[0];//枢轴位置
	return i;
}

template<typename KeyType, typename InfoType>
void QSort(SqList<RedType<KeyType, InfoType>>& L, int i, int j)//递归进行快速排序
{
	if (i < j)
	{
		int pivotLoc = partition(L, i, j);//找到枢轴
		QSort(L, i, pivotLoc - 1);//枢轴左边快速排序
		QSort(L, pivotLoc + 1, j);//枢轴右边快速排序
	}
}

template<typename KeyType, typename InfoType>
void quickSort(SqList<RedType<KeyType, InfoType>>& L)//快速排序
{
	QSort(L, 1, L.length);
}

堆排序

首先要建堆,从有孩子的元素中的最后一个元素开始到第一个元素进行建堆(将该元素与自己的孩子进行比较,若不符合要求,则将自己与孩子交换,然后继续与孩子的孩子比较,直到确定该元素的位置)。建堆完成之后,将堆分成两部分,前面是未交换过的部分,后面是已交换过的部分,初始时,所有元素均视为未交换过。每次将第一个元素与未交换过的元素中的最后一个元素进行交换,再从第一个元素到剩下未交换过的元素中的最后一个进行建堆,直到只剩下第一个元素未交换。
时间复杂度(平均):O(n log⁡n)
时间复杂度(最坏):O(n log⁡n)
空间复杂度:O(1)
稳定性:不稳定

template<typename KeyType, typename InfoType>
void heapAdjust(HeapType<KeyType, InfoType>& H, int s, int m)//调整堆
{//在s到m范围里调整s到合适的位置
	RedType<KeyType, InfoType> R = H.data[s];
	int j;
	for (j = 2 * s; j <= m; j *= 2)//寻找s的后代,直到s比两个儿子都大
	{
		if (j < m && H.data[j].key < H.data[j + 1].key)//寻找s的左右儿子中大的那个,j必须小于m,否则j+1=m+1可能影响结果
			j++;
		if (H.data[j].key <= R.key)//必须用R,不能用s,因为s可能已经与j交换过,此时s其实是存的是交换的j的值
			break;
		H.data[s] = H.data[j];
		s = j;
	}
	H.data[s] = R;
}

template<typename KeyType,typename InfoType>
void heapSort(HeapType<KeyType, InfoType>& H)//堆排序
{
	for (int i = H.length / 2; i > 0; i--)//建堆
		heapAdjust(H, i, H.length);
	for (int i = H.length; i > 1; i--)//交换第一个和最后一个元素,然后重新调整堆
	{
		RedType<KeyType, InfoType>R = H.data[1];
		H.data[1] = H.data[i];
		H.data[i] = R;
		heapAdjust(H, 1, i - 1);
	}
}

基数排序

从低位到高位,对元素的关键字的每一位进行分配和收集。首先进行分配,根据位将每一个元素加入到对应位的静态链表中。然后进行收集,从小到大按每一个静态链表的顺序将元素链接起来。进行完一轮分配和收集之后继续对关键字的下一位进行分配和收集,直至每一位都分配收集完成。
时间复杂度(平均):O(d(n+rd))/O(dn)
时间复杂度(最坏):O(d(n+rd))/O(dn)
空间复杂度:O(rd)
稳定性:稳定

template<typename KeysType>
KeysType ord(KeysType K, int i)//计算第i位的值
{
	KeysType t;
	while (i--)
	{
		t = K;
		t %= 10;
		K /= 10;
	}
	return t;
}

template<typename KeysType, typename InfoType>
void distribute(SLCell<KeysType, InfoType>*& r, int i, ArrType& first, ArrType& end)
{
	for (int j = 0; j < RADIX; j++)//初始化
		first[j] = 0;
	for (int p = r[0].next; p > 0; p = r[p].next)
	{
		int j = ord(r[p].keys[0], i);
		if (first[j] == 0)//还没有元素
			first[j] = p;//作为第一个元素
		else//已经有元素
			r[end[j]].next = p;//作为下一个元素
		end[j] = p;//最后一个元素
	}
}

template<typename KeysType, typename InfoType>
void collect(SLCell<KeysType, InfoType>*& r, int i, ArrType first, ArrType end)
{
	int j;
	for (j = 0; first[j] == 0; j++);//跳过无元素的部分
	r[0].next = first[j];//设置第一个元素
	int e = end[j];//最后一个元素的下标
	while (j < RADIX - 1)
	{
		for (j++; j < RADIX - 1 && first[j] == 0; j++);//跳过无元素的部分
		if (first[j] != 0)//因为找到有元素的部分而退出循环
		{
			r[e].next = first[j];
			e = end[j];
		}
	}
	r[e].next = 0;
}

template<typename KeysType, typename InfoType>
void radixSort(SLList<KeysType, InfoType>& L)//基数排序
{
	ArrType first, end;
	for (int i = 1; i <= L.keynum; i++)//对每一位进行分配和收集
	{
		distribute(L.r, i, first, end);
		collect(L.r, i, first, end);
	}
}

测试

int randint(int start, int end)
{
	return rand() % (end - start) + start;
}

int main()
{
	srand((unsigned int)time(0));
	SqList<RedType<int, string>> L1, L2, L3, L4, L5;
	initSqList(L1);
	initSqList(L2);
	initSqList(L3);
	initSqList(L4);
	initSqList(L5);
	SLList<int, string> L6;

	for (int i = 1; i < randint(10, 15); i++)
	{
		RedType<int, string> t;
		t.key = randint(1, 1000);
		insertSqList(L1, t, i);
		insertSqList(L2, t, i);
		insertSqList(L3, t, i);
		insertSqList(L4, t, i);
		insertSqList(L5, t, i);
	}
	int* data = new int[L1.length];
	for (int i = 0; i < L1.length; i++)
		data[i] = L1.data[i + 1].key;
	initSLList(L6, data, L1.length, 3);

	cout << "L1 = ";
	for (int i = 1; i <= L1.length; i++)
		cout << L1.data[i].key << " ";
	cout << endl;
	cout << "L2 = ";
	for (int i = 1; i <= L2.length; i++)
		cout << L2.data[i].key << " ";
	cout << endl;
	cout << "L3 = ";
	for (int i = 1; i <= L3.length; i++)
		cout << L3.data[i].key << " ";
	cout << endl;
	cout << "L4 = ";
	for (int i = 1; i <= L4.length; i++)
		cout << L4.data[i].key << " ";
	cout << endl;
	cout << "L5 = ";
	for (int i = 1; i <= L5.length; i++)
		cout << L5.data[i].key << " ";
	cout << endl;
	cout << "L6 = ";
	for (int i = 1; i <= L6.recnum; i++)
		cout << L6.r[i].keys[0] << " ";
	cout << endl;

	cout << "L1 after insertSort = ";
	insertSort(L1);
	for (int i = 1; i <= L1.length; i++)
		cout << L1.data[i].key << " ";
	cout << endl;
	cout << "L2 after bubbleSort = ";
	bubbleSort(L2);
	for (int i = 1; i <= L2.length; i++)
		cout << L2.data[i].key << " ";
	cout << endl;
	cout << "L3 after selectSort = ";
	selectSort(L3);
	for (int i = 1; i <= L3.length; i++)
		cout << L3.data[i].key << " ";
	cout << endl;
	cout << "L4 after quickSort = ";
	quickSort(L4);
	for (int i = 1; i <= L4.length; i++)
		cout << L4.data[i].key << " ";
	cout << endl;
	cout << "L5 after heapSort = ";
	heapSort(L5);
	for (int i = 1; i <= L5.length; i++)
		cout << L5.data[i].key << " ";
	cout << endl;
	cout << "L6 after radixSort = ";
	radixSort(L6);
	for (int i = L6.r[0].next; i > 0; i = L6.r[i].next)
		cout << L6.r[i].keys[0] << " ";
	cout << endl;

	system("pause");
	return 0;
}

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值