十大排序算法可以分为比较类和非比较类排序:
类型 | 排序方式 | 算法名称 | 平均 时间复杂度 | 最差 时间复杂度 | 最好 时间复杂度 | 空间复杂度 | 稳定性 |
比较类型 | 交换式 | 冒泡排序 | O(n²) | O(n²) | O(n) | O(1) | 稳定 |
比较类型 | 交换式 | 快速排序 | O(nlog₂n) | O(n²) | O(nlog₂n) | O(nlog₂n)(递归式) | 不稳定 |
比较类型 | 插入式 | 插入排序 | O(n²) | O(n²) | O(n²) | O(1) | 稳定 |
比较类型 | 插入式 | 希尔排序 | O(nlog₂n) | O(n²) | O(n) | O(1) | 不稳定 |
比较类型 | 选择式 | 选择排序 | O(n²) | O(n²) | O(n²) | O(1) | 不稳定 |
比较类型 | 选择式 | 堆排序 | O(nlog₂n) | O(nlog₂n) | O(nlog₂n) | O(1) | 不稳定 |
比较类型 | 拉链式插入 | 归并排序 | O(nlog₂n) | O(nlog₂n) | O(nlog₂n) | O(n) | 稳定 |
非比较类型 | 数组计数 | 计数排序 | O(n) | O(n) | O(n) | O(n) | 稳定 |
非比较类型 | 分桶式 | 桶排序 | O(n) | O(n²) | O(n) | O(n) | 稳定 |
非比较类型 | 按位数排序 | 基数排序 | O(n) | O(n) | O(n) | O(n) | 稳定 |
参考链接:https://www.cnblogs.com/onepixel/articles/7674659.html
P1.h
#pragma once
#include <iostream>
#include <list>
#include <vector>
using namespace std;
//参考链接https://www.cnblogs.com/onepixel/articles/7674659.html
class P1
{
public:
P1();
P1(int *p, int size);
~P1();
//交换排序,插入排序,选择排序,归并排序,都是建立在比较的基础上的排序
/*交换排序*/
void swap_bubbleSort();
void swap_quickSort();
void swap_quickSort(int left,int right);
void swap_quickSort1();//非递归
/*插入排序*/
void insert_simpleInsertSort();
void insert_shellSort();
/*选择排序*/
void choicSort();
void heapSort();
void makeMaxHeap(int star,int end);
/*归并排序*/
void megreSort();
list<int> megreSort_2(list<int>& listAy);
//计数排序,桶排序,基数排序,都是建立在非比较的基础上的排序
/*计数排序*/
void countSort();
/*桶排序*/
void bucketSort();
/*基数排序*/
void orderSort();
void randomSort();
void printfData();
private:
int* m_array;
int m_size;
};
P1.cpp
#include "P1.h"
#include <iostream>
#include <list>
#include <vector>
using namespace std;
P1::P1()
{
}
P1::P1(int *p,int size)
{
m_array = p;
m_size = size;
}
P1::~P1()
{
}
/*冒泡排序*/
void P1::swap_bubbleSort()
{
randomSort();
//排序前
cout << "初始排序:" << endl;
printfData();
for (size_t i = 0; i < m_size; i++)
{
//依次和相邻元素比对,把大的往后面挪动,每执行一次,最大就会在最后,也就是说,m_size-1-i后面的都是拍好序的
for (size_t j = 0; j < m_size-i-1;j++)
{
if (m_array[j] > m_array[j+1])
{
int temp = m_array[j];
m_array[j] = m_array[j+1];
m_array[j+1] = temp;
}
}
cout<<"第"<<i+1<<"次循环"<<endl;
printfData();
}
/*
采用了双重for循环,时间负责度为O(n²)
并且在算法中并未开辟新的内存*,空间复杂度为O(1)
这是最简单的排序算法
*/
}
void P1::swap_quickSort()
{
/*
快速排序的算法分为三步
第一步,先选出标量,用下标0的位置元素的为标量值,在标量后面查找小于标量数值的个数,并将每个小于他的数值依次排在标量后面的N个下标里。
第二步,将标量与排在他后面的最后一个小于他的值的位置交换。这样就实现了,将标量插入在大于和小于他本身之间,将数字分为两个区域,一个是大于标量,一个是小于标量
第三步,将标量所在的位置下标,重新计算出新的两个分治起始范围,使用递归计算结果。
*/
int left = 0;
int right = m_size-1;
randomSort();
cout<<"快速排序开始前"<<endl;
printfData();
swap_quickSort(left,right);
cout << "快速排序结束" << endl;
printfData();
/*
单重for循环加递归,其实理论上来说是N次+两个递归,每个递归里面有有两次O(N),
也就是T(n) = 2T(n/2) + O(n),想看证明的参考这个链接
所有的执行次数加在一块,最坏是无限趋近于O(n²)的
https://blog.csdn.net/oohaha_123/article/details/26558363?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param
在算法中使用了递归,递归的函数没执行完,不会释放函数的内存,也就是函数本身存在堆中,需要在函数执行完才释放内存,所以开辟递归函数的次数
空间复杂度为O(log2n),最坏就是O(n)
这是最简单的排序算法
*/
}
void P1::swap_quickSort(int left,int right)
{
int piovt = left;
int index = piovt + 1;
if (left < right)
{
cout << " 开始时left = " << left << "right=" << right << endl;
printfData();
cout << endl;
//找出后面比piovt一小的元素,并将它放在我后面
for (size_t i = index; i <= right; i++)
{
//如果i位置比piovt的元素小,将元素i与 index位置的元素交换,index++,也就是说,本for循环结束,就会把大于标量和小于标量的值分成两份。
if (m_array[i] < m_array[piovt])
{
int temp = m_array[i];
m_array[i] = m_array[index];
m_array[index] = temp;
index++;
}
cout << "本次标量已将,大小区分开" << endl;
printfData();
}
/*
以上部分略有难懂的地方,举例说明比较贴切。
如 10,8,19,9,16。执行一次交换之后的排列是
10,8,9,19,16
index执行了两次++,index =3,因为标量是10,10后面有两个比他小的值,index初始值=1,执行两次++后值是3。
*/
cout << endl;
/*
for结束就会计算标量应该在的位置,交换开始前,是在起始位置。
交换后可将大于与小于的分开,也就是将标量与最后一个小于他的值的位置交换一下。
*/
index -= 1;//标量应该在的位置就是2,就是9所在的位置下标。
int temp = m_array[index];
m_array[index] = m_array[piovt];
m_array[piovt] = temp;
cout << "本次左右起始,交换完成" << endl;
printfData();
cout << endl;
swap_quickSort(index+1, right);
swap_quickSort(left,index-1);
}
}
void P1::swap_quickSort1()
{
/*
快速排序的非递归,思想是把每次的其实和结束存到堆栈中,先进后出,后进先出的方式,存取,左右的值。
第一次先存入两对left,right
只要堆栈中大于0,即可取出一对数值重新计算,新的left right,知道堆栈中为空。
采用list,并从back处取出数据,取出后,pop,丢掉使用过的数据。
*/
int left = 0;
int right = m_size - 1;
int piovt = left;
int index = piovt + 1;
if (left < right)
{
cout << " 开始时left = " << left << "right=" << right << endl;
printfData();
cout << endl;
for (size_t i = index; i <= right; i++)
{
if (m_array[i] < m_array[piovt])
{
int temp = m_array[i];
m_array[i] = m_array[index];
m_array[index] = temp;
index++;
}
}
index -= 1;
int temp = m_array[index];
m_array[index] = m_array[piovt];
m_array[piovt] = temp;
list<pair<int, int>*> leftRight;
leftRight.push_back(new pair<int,int>(left,index-1));
leftRight.push_back(new pair<int, int>(index+1, right));
while (leftRight.size() > 0)
{
left = leftRight.back()->first;
right = leftRight.back()->second;
leftRight.pop_back();
piovt = left;
index = piovt + 1;
if (left < right)
{
//找出后面比piovt一小的元素,并将它放在我后面
for (size_t i = index; i <= right; i++)
{
//如果i位置比piovt的元素小,将元素i与 index位置的元素交换,index++,也就是说,本for循环结束,就会把大于标量和小于标量的值分成两份。
if (m_array[i] < m_array[piovt])
{
int temp = m_array[i];
m_array[i] = m_array[index];
m_array[index] = temp;
index++;
}
}
index -= 1;
int temp = m_array[index];
m_array[index] = m_array[piovt];
m_array[piovt] = temp;
leftRight.push_back(new pair<int, int>(left, index - 1));
leftRight.push_back(new pair<int, int>(index + 1, right));
}
}
cout << " 结束时:"<< endl;
printfData();
}
}
/*插入排序*/
void P1::insert_simpleInsertSort()
{
/*
插入排序原理:默认前面的数字都是排好序的,使用for循环,依次查找后面每个元素在前面排好序的位置。
不过这个过程有两个重要的步骤。
第一步,先将需要确定位置的数字使用临时变量存储。
第二步,从这个变量依次向前倒叙查找,每找到比自己大的元素,就将这个大的元素后移一个位置。
第三步,确定当前数字的位置后,直接插入
示例,3,2,1,0
第一次默认3是排好序的,从2开始向前查找2在 【3】 中的位置,第一次对比,就将3放到了下标1的位置上
插入后前两个数字【2,3】是排好顺序的
第二次,过程是【2,3,3】,【2,2,3】,最后将1放在起始位置后是【1,2,3】
第三次,过程是【1,2,3,3】,【1,2,2,3】,【1,1,2,3】,最后是【0,1,2,3】
*/
cout << " 开始时:" << endl;
printfData();
for (size_t i = 1; i != m_size; ++i)
{
int index = i - 1;
int current = m_array[i];
while (index>=0)
{
if (m_array[index] > current)
{
m_array[index + 1] = m_array[index];
index--;
}
else
{
break;
}
}
m_array[index + 1] = current;
cout << " 循环一次" << endl;
printfData();
}
cout << endl;
cout << " 结束时:" << endl;
printfData();
/*
时间复杂度为O(n²)
空间复杂度为O(1)
*/
}
void P1::insert_shellSort()
{
/*
希尔排序的过程是从插入排序的基础上改进的,也是时间复杂度第一个突破O(n²)的排序算法
明白了插入排序的原理,再来理解希尔排序其实是很好理解的。
希尔排序和插入排序的不同在于分组,即按照M个元素间隔成一组。每次会在每个组中查找最小的元素并将它放置在最前,且找到大的就往后放。
如【7,8,9,6,3,2,1,0】
第一次排序从,下标4开始依次向后,每次是与 减去4(分组的长度)的元素比较,即
4与0比较如果下标4的比下标0的元素小,就会交换位置。
5与1比较
6与2比较
7与3比较
第一次执行完的效果是
3,2,1,0,7,8,9,6
第二次执行分组长度变成2,
那就会是
从2下标开始依次向后,每次是与减去2的元素比较,即
2与0;
1,2,3,0,7,8,9,6
3与1
1,0,3,2,7,8,9,6
4与2,4与0
1,0,3,2,7,8,9,6
5与3,3与1
1,0,3,2,7,8,9,6
6与4,4与2
1,0,3,2,7,8,9,6
7与5,5与3,3与1
1,0,3,2,7,6,9,8
第三次执行分组长度是1
那就会是
从1下标开始依次向后,每次是与减去2的元素比较,即
1与0;
1,2,3,0,7,8,9,6
2与1,1与0;
1,0,3,2,7,8,9,6
4与3,3与2,2与1,1与0,
依次类推
*/
cout << " 开始时:" << endl;
printfData();
for (int gap =m_size/2; gap > 0; gap=gap/2)
{
for (size_t i= gap; i < m_size; ++i)
{
int current = m_array[i];
int j = i;
while (j-gap>=0 && m_array[j-gap]>current)
{
m_array[j] = m_array[j - gap];
j = j - gap;
}
m_array[j] = current;
}
cout << " 分组数值为"<< gap <<"的比较结束:" << endl;
printfData();
}
cout << endl;
cout << " 结束时:" << endl;
printfData();
}
/*选择排序*/
void P1::choicSort()
{
randomSort();
//排序前
cout << "初始排序:" << endl;
printfData();
for (size_t i = 0; i < m_size; i++)
{
int curIndex = i;
for (size_t j = i+1; j < m_size; j++)
{
if (m_array[j] < m_array[curIndex])
{
curIndex = j;
}
}
int temp = m_array[i];
m_array[i] = m_array[curIndex];
m_array[curIndex] = temp;
cout << "第" << i + 1 << "次循环" << endl;
printfData();
}
/*
选择排序和插入排序都是比较简单的排序算法,具体区别还是与的,冒泡是将最大的元素依次放在最后。
插入排序则是,依次把最小的元素排在前面有序的最后,也就是从后面的元素中选出最小的元素,和当前元素交换位置。
两者是时空复杂度是一样的。
*/
}
void P1::heapSort()
{
/*
先构建一个大顶堆结构的数组排序,堆有点像是完全二叉树的结构。在数组中相关下标是有关系的,也就是说,如果根节点的下标是 i,
那么他的左右子节点的下标就是:2*i+1和2*i+2,所以说,所有的叶子节点就是数组长度一半 +1开始的位置
0
/ \
/ \
1 2
/ \ / \
3 4 5 6
同样,当用数组构建这样一个结构的数据时,他的最左的非叶子节点的下标就是 n/2。
基于堆的结构:是要把最大的根节点的数值排列在第一个位置。相当于每调整一次大顶堆的结构,就会得到一个最大的值。而且和这个值是数组的第一个值。
根据这个规则,我们可以通过以下几步,来实现堆排序
第一步:先构建一个大顶堆结构的数组,将最大值排在第一个
第二步:倒序遍历数组,将大顶堆排序调整后的数值,依次与最后一个元素交换位置。
*/
cout<<"堆排序:"<<endl;
printfData();
for (int i = m_size / 2 - 1; i >= 0; --i)
{
makeMaxHeap(i,m_size-1);
}
for (int i =m_size-1; i >= 0;--i)
{
int temp = m_array[i];
m_array[i] = m_array[0];
m_array[0] = temp;
makeMaxHeap(0, i-1);
}
cout << "排序结束后:" << endl;
printfData();
}
void P1::makeMaxHeap(int start, int end)
{
/*
采用,star-end之间的数构建大顶堆
*/
int dad = start;
int sonLeft = 2 * dad + 1;
while (sonLeft <= end)
{
int sonRight = sonLeft + 1;
if (sonRight<=end && m_array[sonLeft] < m_array[sonRight])
{
sonLeft = sonRight;
}
if (m_array[dad] > m_array[sonLeft])
{
return;
}
else
{
int temp = m_array[dad];
m_array[dad] = m_array[sonLeft];
m_array[sonLeft] = temp;
dad = sonLeft;
sonLeft = 2 * dad + 1;
}
}
}
/*归并排序*/
void P1::megreSort()
{
/*归并排序
一开始一直想不通归并排序的道理。
其实也很简单,为了实现从小到大的目的,将数分成两组,不停的分,直到分到每个组里边只有一个数。
此时两组开始合并
第一次合并肯定是,每个组只有一个数。
遵循谁小谁先排队的规则,将小的排在前面,并从原来分组中删掉这个已经排好位置的数。
形象的来说,两队小孩,依次从小到大排序。那么就从每队的第一个小孩开始比对,谁小谁就先去排队,并排在新队伍的后面。
例如,一队小孩的身高为 2,5,6,10。另一队是,1,2,3,6。
两队归并次序
2与1比,1从原来队列删除,
进入新的队列。
此时三个队列的情况如下:
2,5,6,9
2,3,6
新队列 1
5,6,9
2,3,6
新队列 1,2
5,6,9
3,6
新队列 1,2,2
5,6,9
6
新队列 1,2,2,3
6,9
6
新队列 1,2,2,3,5
9
6
新队列 1,2,2,3,5,6
9
新队列 1,2,2,3,5,6,6
新队列 1,2,2,3,5,6,9
这句是归并后的结果。
利用递归无限分组,分到不能分的时候,开始合并返回,依次回到上次函数的调用的地址,继续往下执行,最终就是排好顺序的结果
*/
cout << "归并开始:" << endl;
printfData();
list<int> list;
for (int i = 0; i != m_size; ++i)
{
list.push_back(m_array[i]);
}
std::list<int> li = megreSort_2(list);
int i = 0;
std::list<int>::iterator iteStar = li.begin();
for (std::list<int>::iterator iter = iteStar; iter!= li.end();++iter)
{
m_array[i] = *iter;
++i;
}
cout << "归并结果:" << endl;
printfData();
/*
归并排序时间复杂度是O(nlogn),T(n)=2T(n/2) +o(n),而且是非常稳定的,所以不存在最坏和最差的情况
由于使用了递归和临时开辟的空间,所以空间复杂度是O(n)
*/
}
list<int> P1::megreSort_2(list<int>& listAy)
{
if (listAy.size() < 2)
{
return listAy;
}
list<int> leftAy;
list<int> rightAy;
int leftEnd = listAy.size() / 2;
list<int>::iterator itEnd = listAy.begin();
for (int i = 0; i != leftEnd; ++i)
{
itEnd++;
}
for (list<int>::iterator iter = listAy.begin(); iter!= itEnd;++iter)
{
leftAy.push_back(*iter);
}
for (list<int>::iterator iter = itEnd; iter != listAy.end(); ++iter)
{
rightAy.push_back(*iter);
}
list<int> newLeftAy = megreSort_2(leftAy);
list<int> newRightAy = megreSort_2(rightAy);
list<int> result;
while (newLeftAy.size() > 0 && newRightAy.size() > 0)
{
if (newLeftAy.front()> newRightAy.front())
{
result.push_back(newRightAy.front());
newRightAy.pop_front();
}
else
{
result.push_back(newLeftAy.front());
newLeftAy.pop_front();
}
}
while (newLeftAy.size() > 0)
{
result.push_back(newLeftAy.front());
newLeftAy.pop_front();
}
while (newRightAy.size() > 0)
{
result.push_back(newRightAy.front());
newRightAy.pop_front();
}
cout << "当前归并结果:" << endl;
//printfData();
for (std::list<int>::iterator iter = result.begin(); iter != result.end(); ++iter)
{
cout << *iter << ",";
}
cout << endl;
return result;
}
//计数排序,桶排序,基数排序,都是建立在非比较的基础上的排序
/*计数排序*/
void P1::countSort()
{
/*
计数排序是最有趣的排序算法,理解起来很简单。因为是比较是整数数值,一般是需要大于0。
算出这个里边最大数字是多少,创建一个这么长的数组,然后利用数值本身当做新数组的下标。并将数值存到这个新的数组中去。
存几次其本身的数值加1,代表有几个这样的数字需要排序。
存的过程,其实就是排序了,最终在新数组中,按照顺序输出,有些数字是多个,就需要多次打印。
*/
cout<<"计数排序前"<<endl;
printfData();
int maxValue = 0;
for (int i = 0; i != m_size; ++i)
{
if (maxValue < m_array[i])
{
maxValue = m_array[i];
}
}
const int size = maxValue + 1;
int *pArray = new int[size]();
for (int i = 0; i != m_size; ++i)
{
int value = m_array[i];
pArray[value] += 1;//有多少个相同的数,这个下标就+多少次
}
//输出新数组的值即可
int star = 0;
for (int i = 0; i != size; ++i)
{
while (pArray[i] > 0)
{
int v = i;
m_array[star] = v;
star++;
pArray[i]--;
}
}
cout << "计数排序后" << endl;
printfData();
}
/*桶排序*/
void P1::bucketSort()
{
cout<<"桶排序的内部排序使用了 归并排序"<<endl;
printfData();
int min = 0;
int max = 0;
for (size_t i = 0; i < m_size; i++)
{
if (m_array[i] > max)
{
max = m_array[i];
}
if (m_array[i] < min)
{
min = m_array[i];
}
}
int bucketsSize = 5;
int bucketsCount = (max - min) / bucketsSize +1;
vector<vector<int>> bucketVector(bucketsCount);
for (int i = 0; i != m_size; ++i)
{
int index = (m_array[i]-min) / bucketsSize;
bucketVector[index].push_back(m_array[i]);
}
int k = 0;
for (int i = 0; i != bucketVector.size(); ++i)
{
list<int> allData;
for (int j = 0; j != bucketVector[i].size(); ++j)
{
allData.push_back(bucketVector[i][j]);
}
allData = megreSort_2(allData);
bucketVector[i].clear();
for (list<int>::iterator iter = allData.begin(); iter != allData.end(); ++iter)
{
bucketVector[i].push_back(*iter);
cout << *iter<<",";
if (k < m_size)
{
m_array[k] = *iter;
}
k++;
}
}
cout<<"排序结束"<<endl;
printfData();
/*
时间复杂度 和内部排序时采用的算法相关,也和桶的数量相关,最极限的情况下每个桶里边只有一个数,效率接近于计数排序。
最差的情况下也是 O((n/m)*log(n/m)) m一般远小于n,所以可以忽略.
空间复杂度为k*d,k为桶的个数,d为桶的空间,也就是O(n)
*/
}
/*基数排序*/
void P1::orderSort()
{
cout << "基数排序开始" << endl;
printfData();
int max = 0;
for (size_t i = 0; i < m_size; i++)
{
if (m_array[i] > max)
{
max = m_array[i];
}
}
int dCcount = 1;
while (abs(max/10)>=1)
{
max = max / 10;
dCcount++;
}
vector<vector<int>> buckets(10);
int num = 1;
int mod = 10;
for (int i = 0; i != dCcount; ++i)
{
for (int j = 0; j != m_size; ++j)
{
//算出当前位数的值
int v = ( m_array[j] % mod) / num;
if (v < 0)
{
v = abs(v);
}
buckets[v].push_back(m_array[j]);
}
int index = 0;
for (size_t n = 0; n < buckets.size(); n++)
{
for (int p = 0; p != buckets[n].size(); ++p)
{
m_array[index++] = buckets[n][p];
}
buckets[n].clear();
}
num *= 10;
mod *= 10;
}
//调整负数的顺序
vector<int> negativeNumber;
for (int n = m_size-1; n >=0; --n)
{
if (m_array[n] < 0)
{
negativeNumber.push_back(m_array[n]);
}
}
for (int n =0;n!=m_size;++n)
{
if (m_array[n] >=0)
{
negativeNumber.push_back(m_array[n]);
}
}
for (int n = 0;n!=m_size;++n)
{
m_array[n] = negativeNumber[n];
}
cout << "排序结束" << endl;
printfData();
/*
时间复杂度为 O(d*2n + 2n),基本上还是线性的,d是最大位数,d远小于n
空间复杂度为O(d+n)
*/
}
void P1::randomSort()
{
int randCount = rand() % 50;
for (size_t j = 0; j != randCount; ++j)
{
for (size_t i = 0; i < m_size; i++)
{
int swapIndex = rand() % m_size;
int temp = m_array[i];
m_array[i] = m_array[swapIndex];
m_array[swapIndex] = temp;
}
}
}
void P1::printfData()
{
for (int i = 0; i != m_size; ++i)
{
cout << m_array[i] << ",";
}
cout << endl;
}
/*
排序总结,
冒泡排序,每次循环将最大的交换到最后的位置,内层for是 size - 1 - i结束
插入排序,每次循环将当前数与前面排好顺序的数比较,算出自己应该插入的位置,执行插入
选择排序,每次循环,从后面选出最小数的下标与当前位置的数交换
基数排序,按照个十百千万位进行 位数值排序,先按照个位排序,在按照百位排序,以此类推
桶排序,计算桶的设置桶的容量,计算最大数与最小数的差值,也就是计算一共多少个数,根据容量计算桶的个数。
分桶放置后,在桶内用归并或者快速排序。可以用来求第K小元素
计数排序,一般只能排列正数
快速排序,属于交换排序。每次循环是从自己后面的第一个数开始,遇到比自己小的就交换到当前位置,在算出自己的位置,与那最终的数交换
希尔排序,希尔排序是分组的插入排序,依次减少分组的大小,每次分组大小是原来的一半,初始分组大小是数组长度的一半,在分组内选择自己的位置
归并排序,归并排序是无限分组,每次从中间将数组分成左右两部分,直到长度为1,开始进行拉练式合并,那个组的第一个小,那个组先进入新的数组排序。
最后把剩余的全部放到新的组中,新的组中的数就是排好序的
堆排序,先构建一个大顶堆,父节点比子节点大,从最右侧的子节点开始构建,倒序构建。第一次构建后,最大的数就在0下标的位置。在利用for每次将最大的数放到最后。
重新构建一次大顶堆,结束后再次将最大的数排列在最后,每次构建堆的数组长度--
相对来说理解程度难一些。
*/
int main(int argc,char *argv[])
{
int a[] = {10,11,12,13,43,45,21,3,4,5,1,2,4,0,123450,-100,-20};
int size = sizeof(a)/sizeof(int);
cout << "size = "<<size << endl;
P1* p = new P1(a, size);
//p->swap_bubbleSort();
//p->choicSort();
p->orderSort();
cout<<atoi("121");
cout << "hello world!" << endl;
system("pause");
return 0;
}