排序算法总结(排序可视化-控制台版)

学完排序,于是写了一个排序过程可视化控制台程序

运行环境:win10

编译器   :vs2017

编程语言:C++

 

上图:

排序算法总结(排序可视化-控制台版)

 

排序算法总结(排序可视化-控制台版)

 


 

代码:

#include<iostream>
#include<iomanip>
#include<windows.h>
#include<vector>	
using namespace std;

const int MaxValue = 50;	//数组中数据的最大值
int num = 0;				//定义全局变量 数组个数

//移动光标位置函数
void  gotoxy(int x, int y)				
{
	COORD pos = { x,y };
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOut, pos); 
}

//清屏函数
void clear(vector<int> buf)				
{
	gotoxy(0, 0);	//调用移动光标位置函数,每次绘图都从0,0位置开始
	for (int i = 0; i < num; i++)
	{
		for (int j = 0; j < MaxValue; j++)
		{
			cout << "  ";
		}
		cout << endl;
	}
}

//绘图函数
void draw(vector<int> buf,int n = 0)
{
	Sleep(100);			//每次绘图的停顿时间(可自定义)
	clear(buf);			//绘图前清空控制台
	gotoxy(0, 0);
	//输出vector当前的排列顺序
	for (int i = n; i < buf.size(); i++)
	{
		//输出该数字,占3格
		cout << setw(3) <<left << buf[i];
		//输出个数等同与该数字的“■”作为图像
		for (int j = 0; j < buf[i]; j++)
		{
			cout << "■";
		}
		cout << endl;
	}
}

////////////////////////         冒泡排序                /////////////////////////
void BubbleSort(vector<int> &buf,int n = num)				
{
	for (int i = 0; i < n; i++)
	{
		bool flag = false;					//表示本次冒泡是否发生了交换
		for (int j = buf.size() - 1; j > i; j--)	//一次冒泡过程
		{
			if (buf[j - 1] > buf[j])		//若为逆序
			{
				swap(buf[j - 1], buf[j]);	//交换
				flag = true;				//表示发生了交换
				draw(buf,0);
			}
		}
		if (flag = false)	//若本次冒泡没有发生交换,则说明表已经有序
		{
			return;
		}
	}
}

/////////////////////////        插入排序                /////////////////////////
void InsertSort(vector<int> &buf , int n = num)			
{
	int i,j;
	for (i = 2; i <= n; i++)		//依次将buf[2]到buf[n]插入到前面的已排序序列
	{
		if (buf[i] > buf[i - 1])	//若buf[i]小于其前驱,需将buf[i]插入有序表
		{
			buf[0] = buf[i];		//存入buf[0],(注意,待排序列下标是1 ~ n
			for (j = i - 1; buf[0] > buf[j]; --j)//从后往前查找待插入位置
			{
				buf[j + 1] = buf[j];			//向后挪位
				draw(buf,1);
			}
			buf[j + 1] = buf[0];				//复制到插入位置
			draw(buf,1);
		}
	}
}

//////////////////////////       折半插入           /////////////////////
void InsertSorts(vector<int> &buf , int n = num)
{
	int i, j, low, high, mid;
	for (i = 2; i <= n; i++)		//依次将buf[2]到buf[n]插入到前面的已排序序列
	{
		buf[0] = buf[i];			//将buf[i]暂存入buf[0]
		low = 1; high = i - 1;		//设置折半查找范围
		while (low <= high)			//折半查找
		{
			mid = (low + high) / 2;	//取中间点
			if (buf[mid] > buf[0])
			{
				high = mid - 1;		//查找左半子表
			}
			else
			{
				low = mid + 1;		//查找右半子表
			}
		}
		for (j = i - 1; j >= high + 1; --j)
		{
			buf[j + 1] = buf[j];			//向后挪位
			draw(buf, 1);
		}
		buf[j + 1] = buf[0];				//插入
		draw(buf, 1);
	}
}

//////////////////////////       希尔排序           ////////////////////////
void ShellSort(vector<int> &buf , int n = num)				
{
	int i, j;
	for (int dk = n / 2; dk >= 1; dk = dk / 2)
	{
		for (i = dk + 1; i <= n; i++)
		{
			if (buf[i] < buf[i - dk])
			{
				buf[0] = buf[i];
				for (j = i - dk; j > 0 && buf[0] < buf[j]; j -= dk)
				{
					buf[j + dk] = buf[j];
					draw(buf, 1);
				}
				buf[j + dk] = buf[0];
				draw(buf, 1);
			}

		}
	}
}

///////////////////////////      快速排序           ///////////////////
//快排--划分操作
int Partition(vector<int> &buf, int lows, int highs)
{
	int pivot = buf[lows];		//将当前表中第一个元素设为基准值,对表进行划分
	while (lows < highs)		//循环跳出条件,当所有元素遍历一遍时lows等于highs
	{
		while (lows < highs&&buf[highs] >= pivot)
		{
			--highs;
		}
		buf[lows] = buf[highs];		//将比基准值小的元素移到左端
		draw(buf, 0);
		while (lows < highs&&buf[lows] <= pivot)
		{
			++lows;
		}
		buf[highs] = buf[lows];		//将比基准值大的元素移到右端
		draw(buf, 0);
	}
	buf[lows] = pivot;				//基准值存放到最终位置
	draw(buf, 0);
	return lows;					//返回存放基准值的位置作为新表划分位置
}
//快排函数主体
void QuickSort(vector<int> &buf,int low = 0,int high = num)
{
	if (low < high)		//若low>=high说明此表只有一个元素或空
	{
		int pivotpos = Partition(buf, low, high);	//划分位置
		QuickSort(buf, low, pivotpos - 1);			//将划分后的左表进入递归
		QuickSort(buf, pivotpos + 1, high);			//将划分后的右表进入递归
	}
} 

//////////////////////////       简单选择排序        ///////////////////////
void SelectSort(vector<int> &buf , int n = num)
{
	for (int i = 0; i < n - 1; i++)
	{
		int min = i;		//记录最小元素位置
		for (int j = i + 1; j < n; j++)	//在buf[i]到buf[n-1]中选择最小元素
		{
			if (buf[j] < buf[min])	
			{
				min = j;//更新最小元素的位置
			}
		}
		if (min != i)
		{
			swap(buf[i], buf[min]);	//与第i个位置交换
			draw(buf,0);
		}
	}
}

/////////////////////////          堆排序           //////////////////////
//堆排序--调整函数
void AdjustDown(vector<int> &buf, int k, int len)
{
	buf[0] = buf[k];	//暂存入buf[0]
	for (int i = 2 * k; i <= len; i *= 2)	//沿key较大的子节点向下筛选
	{
		if (i < len&&buf[i] < buf[i + 1])	
		{
			i++;		//取key较大的子节点的下标
		}
		if (buf[0] >= buf[i])
		{
			break;		//筛选结束
		}
		else
		{
			buf[k] = buf[i];	//将buf[i]调整到双亲结点上
			k = i;				//修改 k 值,以便继续向下筛选
		}
	}
	buf[k] = buf[0];			//被筛选节点的值放入最终位置
}
//堆排序--建立大根堆
void BuildMaxHeap(vector<int> &buf,int len)		
{
	for (int i = len / 2; i > 0; i--)	//从 n/2 到 1 ,反复调整堆
	{
		AdjustDown(buf, i, len);
	}
}
//堆排序主体
void HeapSort(vector<int> &buf , int len = num)
{	
	BuildMaxHeap(buf, len);			//初始建堆
	for (int i = len; i > 1; i--)	//n-1趟的交换和建堆过程
	{
		swap(buf[i], buf[1]);		//输出堆顶元素(和堆底元素交换)
		draw(buf, 1);
		AdjustDown(buf, 1, i - 1);	//把剩余的元素整理成为堆
	}
}


///////////////////////            归并排序         /////////////////////
//归并排序--合并算法
vector<int> buf_copy(20);		//辅助数组
void Merge(vector<int> &buf, int low, int mid, int high)
{
	int i, j, k;
	for (int k = low; k <= high; k++)
	{
		buf_copy[k] = buf[k];	//将buf数组全部复制到buf_copy
	}
	for (i = low, j = mid + 1, k = i; i <= mid && j <= high; k++)
	{
		if (buf_copy[i] <= buf_copy[j])		//比较buf_copy数组左右两段中的元素
		{
			buf[k] = buf_copy[i++];			//将较小值复制到buf中
			draw(buf, 0);
		}
		else
		{
			buf[k] = buf_copy[j++];	
			draw(buf, 0);
		}
	}
	while (i <= mid)
	{
		buf[k++] = buf_copy[i++];		//若前半段未检测完,则剩余部分全部复制进buf
		draw(buf, 0);
	}
	while (j <= high)
	{
		buf[k++] = buf_copy[j++];	//若后半段未检测完,则剩余部分全部复制进buf
		draw(buf, 0);
	}
}
//归并函数主体
void MergeSort(vector<int> &buf, int low = 0, int high = num)
{
	if (low < high)
	{
		int mid = (low + high) / 2;		//从中间划分成两个子序列
		MergeSort(buf, low, mid);		//对左侧子序列进行递归调用
		MergeSort(buf, mid + 1, high);	//对右侧子序列进行递归调用
		Merge(buf, low, mid, high);		//归并
	}
}

/////////////////////////          计数排序          ////////////////////////
//不属于比较排序,没有明显的位置交换过程,无可视化图形
void CountSort(vector<int>&buf)
{
	int max = buf[0];	//定义max
	for (int i = 0; i < buf.size(); i++)	//遍历待排序列找到最大值max
	{
		if (buf[i] > max)
		{
			max = buf[i];
		}
	}
	vector<int> buf_s(max + 1, 0);		//创建一个大小为max+1的数组buf_s
	for (int i = 0; i < buf.size(); i++)	//遍历待排序列,录入buf_s数组
	{
		buf_s[buf[i]]++;		
	}
	for (int i = 0, t = 0; i < max + 1; i++)	//遍历buf_s存入buf数组
	{
		for (int j = buf_s[i]; j > 0; j--, t++)
		{
			buf[t] = i;
		}
	}
	draw(buf);
}


//////////////////            主函数
int main()
{
	int val;				//val作为输入值录入数组
	int flag = 2;			//falg表示用户选择的数据生成方式
	vector<int> buf;		//待排数组
	srand((int)time(0));

	cout << "请输入数组个数:";
	cin >> num;
	cout << "请选择数据的生成方式:" << endl;
	cout << "1,手动输入     2,随机生成" << endl;
	cin >> flag;	
	if (flag == 1)				//读取数据
	{
		for (int i = 0; i < num; i++)
		{
			cin >> val;
			buf.push_back(val%MaxValue);
		}
	}
	else if (flag == 2)			//随机生成数据
	{
		for (int i = 0; i < num; i++)
		{
			val = rand()% MaxValue;
			buf.push_back(val);
		}
	}
	//使num等于最大下标
	num = num - 1;

	//调用排序函数
	QuickSort(buf);

	return 0;
}

 

 

       欢迎大家检查补充,有问题可以在下面评论