根据排序过程中涉及的存储器的不同,排序分为内部排序和外部排序。
内部排序:在计算机随机存储器中进行的排序过程。包括:选择排序(堆排序),插入排序(希尔排序),快速排序、基数排序、归并排序
外部排序:排序过程中需对外存进行访问的排序过程。
一、选择排序
----------------------------------------------------------------------------------------------------------------
1.简单选择排序
原理:1.从左到右遍历,选择最小(大)的元素,与第一个交换,作为第一个。
2.遍历剩下的n-i+1个元素,再选最小(大)的元素,与第i个交换。
3.以此类推,直到排序完毕。
之所以称选择排序,是因为总要选择最小或最大的,选择排序图片。
最差时间复杂度:O(n^2)
最优时间复杂度:O(n^2)
平均时间复杂度:O(n^2)
稳定性:不稳定
#include<iostream>
#include<algorithm>
using namespace std;
/************简单选择排序******************/
void SelectSort(int *a,int len)
{
for(int i = 0;i!=len;i++)
{
int k = i;
int key = a[i];
for(int j=i+1;j!=len;j++)
{
if(a[j] < key)//不断遍历变换最小值
{
k = j;
key = a[j];
}
}
if(k != i)
swap(a[i],a[k]);//把第i次遍历的最小值和a[i[交换
cout << a[i] <<" ";
}
}
int main()
{
int length = 0;
int i = 0;
cin >> length;
int a[100] = {0};
for(;i!=length;i++)
cin>>a[i];
SelectSort(a,length);
system("pause");
return 0;
}
-----------------------------------------------------------------------------------------------------------------
2.树形选择排序(锦标赛排序)
原理:对N个记录的关键字进行两两比较,选出最小(大)的n/2个数,再进行新一轮的比较,直到选出最小(大)的。
1.把N个数放到完全二叉树的叶子节点,两两比较,选出最小的作为根节点,且保存到数组中
2.把最小的原始值设为无穷大,从那个地方开始新一轮比较
第一次需要比较n-1次,之后都是log2(n)次
复杂度:O(n*log2 n)
/************树形选择排序or锦标赛排序******************/
struct TreeNode{
int data;
int arr_index;//记录当前节点是原数组的哪个元素
};
TreeNode *tree;
void UpdataTree(TreeNode tree[],int index)//从上一次胜出的节点中开始更新
{
while(index)
{
if(index % 2)//如果是左孩子
{
if(tree[index].data <= tree[index+1].data)//左孩子小于右孩子
{
tree[(index-1)/2].data = tree[index].data;//更新父节点的值
tree[(index-1)/2].arr_index = tree[index].arr_index;//更新父节点的arr_index
}
else
{
tree[(index-1)/2].data = tree[index+1].data; //更新父节点的
tree[(index-1)/2].arr_index = tree[index+1].arr_index; //更新父节点的arr_index
}
index = index/2;//更新索引,准备比较上一层父节点及其兄弟
}
else//如果是右孩子
{
if(tree[index-1].data <= tree[index].data)//左孩子小于右孩子
{
tree[index/2-1].data = tree[index-1].data; //更新父节点的值
tree[index/2-1].arr_index = tree[index-1].arr_index;//更新父节点的arr_index
}
else//左孩子大于右孩子
{
tree[index/2-1].data = tree[index].data; //更新父节点的值
tree[index/2-1].arr_index = tree[index].arr_index; //更新父节点的arr_index
}
index = index/2-1;//更新索引,准备比较上一层父节点及其兄弟
}
} //while结束时得到一个胜者
}
void ChampionSort(int arr[],int num)//锦标赛排序
{
int LeafNodeSize= 1;//满二叉树的叶子节点数
int height = 1;//满二叉树的高度
while(LeafNodeSize < num)//循环结束后,满二叉树叶子节点应该是2的幂
{
LeafNodeSize*=2;
++height;
}
int const TreeSize = LeafNodeSize *2 -1;//满二叉树所有节点个数正好是叶子个数的两倍
tree = new TreeNode[TreeSize];//动态分配比较树
int IndexLeafStart = LeafNodeSize -1;//叶子节点的开始下标,即最后一行
for(int i = IndexLeafStart,j=0;i<TreeSize;i++)//.初始化树,把Treesize个数a[0]……a[treesize]依次放到叶子节点tree[IndexLeafStart]上
{
if(j < num)
{
tree[i].data = arr[j];
tree[i].arr_index = j;
j++;
}
else
{
tree[i].data = DATA_MAX;
tree[i].arr_index = -1;
}
}
for(int k = TreeSize-1;k>1;k-=2)//左右子树两个节点比较,推选出小的作为父节点,求父节点标号
{
if(tree[k-1].data <= tree[k].data)
{
tree[k/2-1].data = tree[k-1].data; //更新父节点的值
tree[k/2-1].arr_index = tree[k-1].arr_index; //更新父节点的arr_index
}
else
{
tree[k/2-1].data = tree[k].data; //更新父节点的值
tree[k/2-1].arr_index = tree[k].arr_index; //更新父节点的arr_index
}
} //此for结束后既得到首个获胜者树
for(int m = 0;m<num-1;m++)//处理剩余的num-1个元素
{
arr[m]=tree[0].data; //每次都将获胜树存入数组
int winIndex = tree[0].arr_index + IndexLeafStart;//直接保存获胜者的根信息
tree[winIndex].data = DATA_MAX; //把获胜者的值设为无穷大之后再一轮比较
UpdataTree(tree, winIndex);
cout << arr[m] <<" ";
}
arr[num-1] = tree[0].data;
cout << arr[num-1] <<" ";
delete [] tree;
}
<span style="font-weight: bold; color: rgb(204, 0, 0); font-size: 24px; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">---------------------------------------------------------------------------------------------------------------------</span>
3.堆排序
1. 堆的性质:子节点的值总是小于他的父节点(大顶堆)
通常堆用一位数组来实现,起始数组为a[0]的情形下,节点i的左右节点为:
其左子节点的下标为 (2*i+1);
其右子节点的下标为 (2*i+2);
2. 原理:分为三步:
[1]最大堆调整:
在假定节点的子节点的二叉树都是最大堆的前提下,比较父节点和子节点,若小于子节点则调整,确保i为根的子树为最大堆。主要用 于刚开始创建最大堆和堆排序后调整a[0]和a[i]时,让a[0]比较后调整下沉,使新的堆成为最大堆。
[2]创建最大堆
将数组按顺序层序放在堆中,然后对所有非叶子节点进行最大堆调整,进行n/2次调整
[3]堆排序
创建最大堆以后,依次将末节点与根节点交换,删除末节点(即把length-1),然后从上到下对根节点进行最大对调整,直到堆中节点数为1,排序结束
最差时间复杂度:O(nlogn)
最优时间复杂度:O(nlogn)
平均时间复杂度:O(nlogn)
稳定性:不稳定
/********************堆排序*********************************
1,堆调整
2.创建最大堆
3.堆排序
****************** ****************** *********************/
void MaxHeapAdjust(int a[],int i,int n)//对节点i进行调整,n是数组元素个数
{
int largest = 0;
int left = i*2 + 1;//节点i的左节点
int right = i*2 + 2;//节点i的右节点
if(left< n && a[left]>a[i])//左节点和父节点比较
largest =left;
else
largest = i;
if(right<n && a[right]>a[largest])//如果有右节点,且左小于右
largest = right;
if(i != largest)//如果最大节点不是父节点
{
swap(a[i],a[largest]);
MaxHeapAdjust(a,largest,n);//下降父节点,跟子树最大堆比,其实经过创建最大堆时,子树都为最大堆了
}
}
//创建最大堆
void BuildMaxHeap(int a[],int length)
{
for(int i = length/2-1;i>=0;i--)//从非叶子节点开始进行最大堆调整
{
MaxHeapAdjust(a,i,length);
}
}
//堆排序
void HeapSort(int a[],int length)
{
BuildMaxHeap(a,length);
for(int i = length-1;i>=0;i--)//从堆中删除数
{
swap(a[0],a[i]);
//cout << a[i] <<" ";
MaxHeapAdjust(a,0,i);
}
for(int i = 0;i!=length;i++)
{
cout << a[i]<<" ";
}
}
至此,选择排序总结完毕。
全部代码如下:
#include<iostream>
#include<algorithm>
#define DATA_MAX (int)((unsigned)(~(int)0)>>1)
using namespace std;
/************选择排序******************/
void SelectSort(int *a,int len)
{
for(int i = 0;i!=len;i++)
{
int k = i;
int key = a[i];
for(int j=i+1;j!=len;j++)
{
if(a[j] < key)//不断遍历变换最小值
{
k = j;
key = a[j];
}
}
if(k != i)
swap(a[i],a[k]);//把第i次遍历的最小值和a[i[交换
cout << a[i] <<" ";
}
}
/************树形选择排序or锦标赛排序******************/
struct TreeNode{
int data;
int arr_index;//记录当前节点是原数组的哪个元素
};
TreeNode *tree;
void UpdataTree(TreeNode tree[],int index)//从上一次胜出的节点中开始更新
{
while(index)
{
if(index % 2)//如果是左孩子
{
if(tree[index].data <= tree[index+1].data)//左孩子小于右孩子
{
tree[(index-1)/2].data = tree[index].data;//更新父节点的值
tree[(index-1)/2].arr_index = tree[index].arr_index;//更新父节点的arr_index
}
else
{
tree[(index-1)/2].data = tree[index+1].data; //更新父节点的
tree[(index-1)/2].arr_index = tree[index+1].arr_index; //更新父节点的arr_index
}
index = index/2;//更新索引,准备比较上一层父节点及其兄弟
}
else//如果是右孩子
{
if(tree[index-1].data <= tree[index].data)//左孩子小于右孩子
{
tree[index/2-1].data = tree[index-1].data; //更新父节点的值
tree[index/2-1].arr_index = tree[index-1].arr_index;//更新父节点的arr_index
}
else//左孩子大于右孩子
{
tree[index/2-1].data = tree[index].data; //更新父节点的值
tree[index/2-1].arr_index = tree[index].arr_index; //更新父节点的arr_index
}
index = index/2-1;//更新索引,准备比较上一层父节点及其兄弟
}
} //while结束时得到一个胜者
}
void ChampionSort(int arr[],int num)//锦标赛排序
{
int LeafNodeSize= 1;//满二叉树的叶子节点数
int height = 1;//满二叉树的高度
while(LeafNodeSize < num)//循环结束后,满二叉树叶子节点应该是2的幂
{
LeafNodeSize*=2;
++height;
}
int const TreeSize = LeafNodeSize *2 -1;//满二叉树所有节点个数正好是叶子个数的两倍
tree = new TreeNode[TreeSize];//动态分配比较树
int IndexLeafStart = LeafNodeSize -1;//叶子节点的开始下标
for(int i = IndexLeafStart,j=0;i<TreeSize;i++)//.初始化树
{
if(j < num)
{
tree[i].data = arr[j];
tree[i].arr_index = j;
j++;
}
else
{
tree[i].data = DATA_MAX;
tree[i].arr_index = -1;
}
}
for(int k = TreeSize-1;k>1;k-=2)//求父节点标号
{
if(tree[k-1].data <= tree[k].data)
{
tree[k/2-1].data = tree[k-1].data; //更新父节点的值
tree[k/2-1].arr_index = tree[k-1].arr_index; //更新父节点的arr_index
}
else
{
tree[k/2-1].data = tree[k].data; //更新父节点的值
tree[k/2-1].arr_index = tree[k].arr_index; //更新父节点的arr_index
}
} //此for结束后既得到首个获胜者树
for(int m = 0;m<num-1;m++)//处理剩余的num-1个元素
{
arr[m]=tree[0].data; //每次都将获胜树存入数组
int winIndex = tree[0].arr_index + IndexLeafStart;//直接保存获胜者的根信息
tree[winIndex].data = DATA_MAX; //把获胜者的值设为无穷大之后再一轮比较
UpdataTree(tree, winIndex);
cout << arr[m] <<" ";
}
arr[num-1] = tree[0].data;
cout << arr[num-1] <<" ";
delete [] tree;
}
/********************堆排序*********************************
1,堆调整
2.创建最大堆
3.堆排序
****************** ****************** *********************/
void MaxHeapAdjust(int a[],int i,int n)//对节点i进行调整,n是数组元素个数
{
int largest = 0;
int left = i*2 + 1;//节点i的左节点
int right = i*2 + 2;//节点i的右节点
if(left< n && a[left]>a[i])//左节点和父节点比较
largest =left;
else
largest = i;
if(right<n && a[right]>a[largest])//如果有右节点,且左小于右
largest = right;
if(i != largest)//如果最大节点不是父节点
{
swap(a[i],a[largest]);
MaxHeapAdjust(a,largest,n);//下降父节点,跟子树最大堆比,其实经过创建最大堆时,子树都为最大堆了
}
}
//创建最大堆
void BuildMaxHeap(int a[],int length)
{
for(int i = length/2-1;i>=0;i--)//从非叶子节点开始进行最大堆调整
{
MaxHeapAdjust(a,i,length);
}
}
//堆排序
void HeapSort(int a[],int length)
{
BuildMaxHeap(a,length);
for(int i = length-1;i>=0;i--)//从堆中删除数
{
swap(a[0],a[i]);
//cout << a[i] <<" ";
MaxHeapAdjust(a,0,i);
}
for(int i = 0;i!=length;i++)
{
cout << a[i]<<" ";
}
}
int main()
{
int length = 0;
int i = 0;
cout << "请输入排序数组长度:" << endl;
cin >> length;
int a[100] = {0};
cout << "请输入排序数组:" << endl;
for(;i!=length;i++)
cin>>a[i];
cout << "简单选择排序:" << endl;
SelectSort(a,length);
cout << endl;
cout << "锦标赛排序:" << endl;
ChampionSort(a,length);
cout << endl;
cout << "堆排序:" << endl;
HeapSort(a,length);
cout << endl;
system("pause");
return 0;
}