目录
7.2 优化快速排序: (三数取中) 非递归分治 --> 不会堆溢出
1.大小堆的创建、如何放元素、获取队头元素:
基于比较的排序方法:
排序方法 | 最好 | 平均 | 最坏 | 空间复杂度 | 稳定性 |
冒泡排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
插入排序 | O(n) | O(n^2) | O(n^2) | O(1) | 稳定 |
选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 |
希尔排序 | O(n) | O(n^1.3) | O(n^1.5) | O(1) | 不稳定 |
堆排序 | O(n * log(n)) | O(n * log(n)) | O(n * log(n)) | O(1) | 不稳定 |
快速排序 | O(n * log(n)) | O(n * log(n)) | O(n^2) | O(log(n)) ~ O(n) | 不稳定 |
归并排序 | O(n * log(n)) | O(n * log(n)) | O(n * log(n)) | O(n) | 稳定 |
稳定的排序方式:冒泡、直接插入、归并排序
冒泡、选择、直接插入排序都是比较简单的排序,
1.堆的排序
升序,则创建大根堆
/*从小到大排序:
1. 调整为大根堆
2. 0下标和最后一个未排序的元素进行交换
3. end--
* */
public void heapSort() {
int end = usedSize-1;
while (end > 0) {
int tmp = elem[0];
elem[0] = elem[end];
elem[end] = tmp;
shiftDown(0,end); //向下调整
end--;
}
}
2.直接插入排序
时间复杂度: O(N^2) --》最好的情况O(N):数据有序
空间复杂度: O(1)
稳定性: 稳定
若一个本身就不稳定的排序,是不会变成稳定的排序的
public class testSorts {
public static void insertSort(int[] array) {
for (int i = 1; i < array.length; i++) {
int tmp = array[i]; //开辟一块内存tmp存放从第二个元素开始的array[i]元素
int j = i-1; //j始终在i的前一个位置
for (; j >= 0 ; j--) {
if (array[j] > tmp) { //如果j下标大于tmp的值,则将array[j]往后移(升序)
array[j+1] = array[j]; //也即是ij对应元素互换
}else { //不大于(<=)就不移动,默认是升序排列,退出此步操作
// array[j+1] = tmp;
break; //只要j回退到比tmp小的元素就结束这次比较
}
}//j为负数时候
//j回退到小于0的地方
array[j+1] = tmp;
}
}
3.希尔排序(缩小增量法)
分组,组内是直接排序(是对直接插入排序的优化)
希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。
1. 希尔排序是对直接插入排序的优化。
2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。
时间复杂度【和增量有关系】:O(N^1.3到N^1.5)最好和最坏 --》最好的情况O(N):数据有序
空间复杂度:O(1)
稳定性:不稳定
交换过程中若发生跳跃式交换,则是不稳定的
// gap:组数 array:待排数列
public static void shell(int[] array,int gap) { //此函数shell也即是直接插入排序方法
for (int i = gap; i < array.length; i++) { //i从下标为gap的值开始
int tmp = array[i];
int j = i-gap;
for (; j >=0; j -= gap) {
if (array[j] > tmp) { //tmp是i处的值,j在左边,而array[j]值更大,说明不是有序的,需要更换位置
array[j+gap] = array[j]; //j+gap也即是i,此处为交换ij对应元素
}else { //如果值符合要求,则位置不变动,退出此次循环即可,继续下一步的循环:i+1
break;
}
}
array[j+gap] = tmp; //j < 0, tmp不变化,也即是将i放回原位置
}
}
public static void shellSort(int[] array) {
int gap = array.length;
while (gap > 1) { //进行分组,预排序
shell(array,gap);
gap /=2;
}
shell(array,1); //保证最后是一组
}
4.选择排序
保持第一个元素不动,后续元素依次与此进行大小比较,后面值小的话进行位置交换
时间复杂度【和增量有关系】: O(N^2) 对数据不敏感
空间复杂度: O(1)
稳定性: 不稳定
public static void swap(int[] array,int i,int j) {
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
public static void selectSort1(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if(array[i] > array[j]) { //升序排列 降序排列:array[i] < array[j]
swap(array,i,j);
}
}
}
}
//优化选择排序
public static void selectSort(int[] array) {
for (int i = 0; i < array.length; i++) {
int minIndex = i;
for (int j = i + 1; j < array.length; j++) {
if (array[j] < array[minIndex]) {
minIndex = j;
}
}
swap(array,i,minIndex);
}
}
5.堆排序
升序(从小到大):建立大根堆
基本原理:选择排序,但不使用遍历的方式,而是通过堆来选择查找无序区间的最大的数。
时间复杂度:O(N*log2(N))
空间复杂度: O(1)
稳定性: 不稳定
解析:
1.先创建大根堆createHeap
2.0下标和end下标交换
3.继续调整当前堆为大根堆shiftDown
4.end--,继续交换
public static void heapSort(int[] array) { //堆排序
createHeap(array); //首先创建大根堆---->0下标和最后一个下标end(array.leng-1)进行位置交换
int end = array.length-1; //end为最后一个元素下标
while (end > 0) { //循环条件:end 》 0,当end走到0下标时完成交换
swap(array,0,end); //进行交换,交换结束之后调整为大根堆
shiftDown(array,0,end); //调整为大根堆之后,根节点依旧是除开end之外的最大值
end--; //此时再继续进行交换(end和0),继续循环
}
}
public static void createHeap(int[] array) {
//child = array.length-1;
//大根堆parent往后走,最初只会知道最后一个孩子的下标array.length-1,由此可得对应parent
for (int parent = (array.length-1-1)/2; parent >= 0 ; parent--) {
shiftDown(array,parent,array.length); //大根堆:向下调整,
}
}
public static void shiftDown(int[] array,int parent,int len) {
int child = 2*parent+1; //左孩子
while (child < len) { //循环条件:孩子child下标在数组长度范围内
//child+1 < len说明至少有一个右孩子--》array[child] < array[child+1]表明右孩子更大,
if (child+1 < len && array[child] < array[child+1]) { //此处child+1是右孩子,没有超过数组长度len,且左孩子<右孩子
child++; //变为最后一个孩子,且右孩子大于左孩子
}
//child下标是左右孩子最大值的下标
if (array[child] > array[parent]) { //如果孩子对应值>父亲节点,则进行交换(保持根(父亲)节点>孩子)
swap(array,child,parent);
parent = child; //交换之后继续往后走,父亲节点走到子节点位置,而子节点继续向后走
child = 2*parent+1;
}else { //孩子节点不大于父亲节点,则不用交换,退出break即可
break;
}
}
}
6.冒泡排序
在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序
时间复杂度】:O(N^2)
空间复杂度:O(1)
稳定性:稳定
//========================未优化冒泡排序:====================================//
public static void bubbleSorts0(int[] array) {
for (int i = 0; i < array.length-1; i++) {
for (int j = 0; j < array.length-1-i; j++) { //每一次会确定一个有序值放在最后,因此,j的长度每次也会减少
if (array[j] > array[j+1]) {
swap(array,j+1,j);
}
}
}
}
//========================优化冒泡排序:====================================//
//2.时间复杂度】:最坏O(N^2) 最好O(N)
public static void bubbleSorts(int[] array) {
for (int i = 0; i < array.length-1; i++) {
boolean isSorted= false;
for (int j = 0; j < array.length-1-i; j++) { //每一次会确定一个有序值放在最后,因此,j的长度每次也会减少
if (array[j] > array[j+1]) {
swap(array,j+1,j);
isSorted = true;
}
}
if (isSorted == false) {
break;
}
}
}
7. 快速排序
7.1未优化快速排序:递归完成
时间复杂度】:最坏O(N^2) 最好O(N*log2(N))
空间复杂度:O(N)
稳定性:不稳定
解析:
1.选择基准,将第一个元素存放到tmp,从后往前找,若比tmp大,end--,继续往前寻找,不变换位置;若比tmp小的值放到第一个位置start下标处;
2.然后从start开始遍历,找>tmp的值,将其放入到end--停留的位置处
3.继续执行上述操作,继续找比基准元素tmp大或者小元素并移动位置,----》左边的值<基准,右边>基准。
4.继续将第一个元素作为基准元素,重复上述操作
//start:起始下标 end:最后一个元素下标 pivot:基准下标
//1.找基准元素 :
public static int partition(int[] array, int start, int end) {//找基准的函数
int tmp = array[start]; // 基准找完之后从后找
while (start < end) {
while (start < end && array[end] >= tmp) { //比基准元素大,则不移动该元素,向前找end--
end--;
}
//走完之后end下标遇到 < tmp的值
array[start] = array[end]; //遇到的值<tmp,则将其放入start位置
while (start < end && array[start] <= tmp) {
start++; //array[start] 小于基准tmp元素,则不移动,继续向前遍历,start++
}
//当array[start] > tmp,则向后移动到 上一步的end的位置
array[end] = array[start];
}
array[start] = tmp; //start 和end相遇,将tmp放到这个位置,至此/第一次循环结束,得到基准元素左边的值小于基准,右边的值大于基准,
return start; //返回start或者end,也即是相遇的位置
}
//找到基准元素之后,对其左右进行排序
public static void quick0(int[] array,int left,int right) { //类似二叉树,分而治之,先找到基准,然后执行左边和右边
if (left >= right) { //当左右相遇的时候,退出递归,直接return。
return;
}//退出之后继续找第一个元素作为基准
int pivot = partition(array,left,right);//先找到基准,在分别递归左边和右边
quick(array,left,pivot-1);
quick(array,pivot+1,right);
}
public static void quickSort0(int[] array) { //快速排序:完成对一个数组的排序
quick(array,0, array.length-1);// 对数组array,从下标0到array.length-1进行排序--》快速排序也即是递归quick的一个过程
}
7.2 优化快速排序: (三数取中) 非递归分治 --> 不会堆溢出
时间复杂度】:最坏O(N^2) 最好O(N)
空间复杂度:O(1)
稳定性:不稳定
解析:
1.选择基准,将第一个元素存放到tmp,从后往前找,若比tmp大,end--,继续往前寻找,不变换位置;若比tmp小的值放到第一个位置start下标处;
2.然后从start开始遍历,找>tmp的值,将其放入到end--停留的位置处
3.继续执行上述操作,继续找比基准元素tmp大或者小元素并移动位置,----》左边的值<基准,右边>基准。
4.继续将第一个元素作为基准元素,重复上述操作
private static int findMidValIndex(int[] array,int start,int end) {
int mid = start + ((end - start) >>> 1); // >>> 1:右移1位--》也即是除2
if (array[start] < array[end]) {
if (array[mid] < array[start]) {
return start;
} else if (array[mid] > array[end]) {
return end;
} else {
return mid;
}
}else {
if (array[mid] > array[start]) {
return start;
} else if (array[mid] < array[end]) {
return end;
}else {
return mid;
}
}
}
public static void quick(int[] array,int left,int right) { //类似二叉树,分而治之,先找到基准,然后执行左边和右边
if (left >= right) { //当左右相遇的时候,退出递归,直接return。
return;
}
//1.如果区间内的数据在排序过程中,如果小于某个范围(如40),则可直接进行直接插入排序
if (right-left+1 <=40) {
insertSort(array);
return;
}
//2.退出之后继续找中间元素作为基准(三数取中)
int midValIndex = findMidValIndex(array,left,right);
swap(array,left,right);
int pivot = partition(array,left,right);//先找到基准,在分别递归左边和右边
quick(array,left,pivot-1);
quick(array,pivot+1,right);
}
public static void quickSort(int[] array) { //快速排序:完成对一个数组的排序
quick(array,0, array.length-1);// 对数组array,从下标0到array.length-1进行排序--》快速排序也即是递归quick的一个过程
}
7.3 非递归 快速排序:
解析:
1.找基准
2.借用栈 --》放入左区间下标、和右区间下标-->相对于基准的左右(四个下标值)--》前提是基准pivot左右都有俩元素
3.弹出栈顶两个元素,也即是右边区间的两个下标
4.然后再弹出的两个下标区间内找基准:第一个下标元素放入tmp,从最后一个下标往前依次与tmp比较, 当后面的值比tmp小时,则将其移动到弹出区间的第二个位置
public static void quickSorts(int[] array) {
Stack<Integer> stack = new Stack<>();
int left = 0;
int right = array.length-1;
int pivot = partition(array,left,right);
if (pivot > left+1) { //说明左边有至少俩元素
stack.push(left); //将左边下标放入堆里
stack.push(pivot-1);
}
if (pivot < right-1) { //说明右边边有至少俩元素
stack.push(pivot+1); //将右边下标放入堆里
stack.push(right);
}
//查看栈是否为空,不为空执行以下循环:弹出两个元素作为左右下标继续找基准
while (!stack.isEmpty()) {
right = stack.pop();
left = stack.pop();
pivot = partition(array,left,right);
if (pivot > left+1) { //说明左边有至少俩元素
stack.push(left); //将左边下标放入堆里
stack.push(pivot-1);
}
if (pivot < right-1) { //说明右边边有至少俩元素
stack.push(pivot+1); //将右边下标放入堆里
stack.push(right);
}
}
}
//1.找基准元素 :
public static int partition(int[] array, int start, int end) {//找基准的函数
int tmp = array[start]; // 基准找完之后从后找
while (start < end) {
while (start < end && array[end] >= tmp) { //比基准元素大,则不移动该元素,向前找end--
end--;
}
//走完之后end下标遇到 < tmp的值
array[start] = array[end]; //遇到的值<tmp,则将其放入start位置
while (start < end && array[start] <= tmp) {
start++; //array[start] 小于基准tmp元素,则不移动,继续向前遍历,start++
}
//当array[start] > tmp,则向后移动到 上一步的end的位置
array[end] = array[start];
}
array[start] = tmp; //start 和end相遇,将tmp放到这个位置,至此/第一次循环结束,得到基准元素左边的值小于基准,右边的值大于基准,
return start; //返回start或者end,也即是相遇的位置
}
8. 归并排序
8.1 递归实现 归并排序
归并排序:是建立在归并操作上的一种有效的排序算法,采用分治法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
将两个有序表合并成一个有序表,称为二路归并。
时间复杂度】:O(N*log(N))
空间复杂度:O(N)
稳定性:稳定 若(array[s1] <= array[s2],不取等号则是不稳定的
public static void merSort(int[] array) { //合并有序的两个数组
mergeSortInternal(array,0,array.length-1);
}
public static void mergeSortInternal(int[] array,int low,int high) {
if (low >= high) {
return;
}
int mid = low + (high-low) >>>1; //(low+high)/2
mergeSortInternal(array,low,mid); //左边
mergeSortInternal(array,mid+1,high); //右边
merge(array,low,mid,high);//合并
}
public static void merge(int[] array,int low,int mid,int high){ //合并两个有序数组:二路归并
int[] array3 = new int[high-low+1];//创建一个新数组用于存放元素
int k = 0; //k为新数组下标
int s1 = low; //有序数组1
int e1 = mid;
int s2 = mid+1; //有序数组2
int e2 = high;
while (s1 <= e1 && s2 <= e2) {
if (array[s1] <= array[s2]) { //比较两个有序数组第一个元素的大小,小的元素放入新数组
array3[k++] = array[s1++];
}else { // 另一个数组元素小 array2[s2] < array1[s1]
array3[k++] = array[s2++];
}
}
while (s1 <= e1) { //此时说明第一个数组还剩下数据没移动到新数组,直接将其放入到新数组即可
array3[k++] = array[s1++];
}
while (s2 <= e2) {
array3[k++] = array[s2++];
}
//拷贝array数组元素,放入原数组
for (int i = 0; i < k; i++) {
array[i+low] = array3[i];
}
}
8.2 归并排序 ---->非递归排序
时间复杂度】:O(N*log(N))
空间复杂度:O(N)
稳定性:稳定 若(array[s1] <= array[s2]不取等号则是不稳定的
//定义i下标遍历数组
public static void merSort1(int[] array) { //合并有序的两个数组
int gap = 1;
int nums = 1;
while (gap < array.length) {
//每次都要对数组进行遍历
for (int i = 0; i < array.length; i +=nums*2) {
int left = i;
int mid = left+nums-1;
if (mid >= array.length) { //防止越界
mid = array.length-1;
}
int right = mid+nums;
if (right >= array.length) {
right = array.length-1;
}
merge1(array,left,mid,right);
}
nums *=2;
}
}
public static void merge1(int[] array,int low,int mid,int high){ //合并两个有序数组
int[] array3 = new int[high-low+1];//创建一个新数组用于存放元素
int k = 0;
int s1 = low;
int e1 = mid;
int s2 = mid+1;
int e2 = high;
while (s1 <= e1 && s2 <= e2) {
if (array[s1] <= array[s2]) {
array3[k++] = array[s1++];
}else { // 另一个数组元素小 array2[s2] < array1[s1]
array3[k++] = array[s2++];
}
}
while (s1 <= e1) { //此时说明第一个数组还剩下数据没移动到新数组,直接将其放入到新数组即可
array3[k++] = array[s1++];
}
while (s2 <= e2) {
array3[k++] = array[s2++];
}
//拷贝array数组元素,放入原数组
for (int i = 0; i < k; i++) {
array[i+low] = array3[i];
}
}
9. 合并两个有序数组
解析:
1.将两个有序数组合并为一个数组:定义两个数组的起始下标-->也即是(二路归并)
2.比较两个数组第一个元素的大小,将小的元素放入到一个新的数组,有小元素的数组继续向后走
3.将其的第二个元素与另一个数组的第一个元素进行比较,小的放入新的数组而各个位置;
4.重复以上2和3步骤---》若其中一个数组走完(下标超出length-1),直接将另一个数组剩下的的元素放入新数组即可,至此完成两个数组的合并
public static int[] mergeArray(int[] array1,int[] array2) {
int[] array3 = new int[array1.length+array2.length];//创建一个新数组用于存放元素
int k = 0; //新数组下标
int s1 = 0; //数组1起始下标
int e1 = array1.length-1;
int s2 = 0; //数组2起始下标
int e2 = array2.length-1;
while (s1 <= e1 && s2 <= e2) { // 当两个数组都在下表范围内时,比较元素大小
if (array1[s1] <= array2[s2]) { //数组1更小则将其让如新数组
array3[k++] = array1[s1++];
}else { // 数组2元素小 array2[s2] < array1[s1]
array3[k++] = array2[s2++];
}
}
//此时已经有一个数组走完,另一个数组还剩下元素,只需将剩下的直接放入新数组即可
while (s1 <= e1) { //此时说明第一个数组还剩下数据没移动到新数组,直接将其放入到新数组即可
array3[k++] = array1[s1++];
}
while (s2 <= e2) {
array3[k++] = array2[s2++];
}
return array3;
}
10. 计数排序:
适用于有N个数,数据范围:0-N之间
解析:
1.先创建一个计数数组count[]用于存放每个数组中每个元素出现的次数-->count数组范围是原数组数据的最小值到最大值
2.求数组的最大值maxval和最小值minval--->maxval-minval+1=count[]数组长度
3.count[array[i]-minval]
当前代码不稳定 但是计数排序的本质是稳定的
public static void countingSort(int[] array) {
int maxVal = array[0];
int minVal = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] < minVal) {
minVal = array[i];
}
if (array[i] > maxVal) {
maxVal = array[i];
}
}
//此时找到了最大值和最小值
int[] count = new int[maxVal-minVal+1]; //默认都是0
//统计每个数据出现的次数
for (int i = 0; i < array.length; i++) { //原数组的值作为新数组count的下标
int index = array[i];//index为新数组count下标
count[index-minVal]++; //计数
}
//此时说明计数数组中已经统计完每个数据出现的次数,后面只需遍历数组,将数据写出来即可,最后返回数组
int indexArrray = 0; //定义一个新下标
for (int i = 0; i < count.length; i++) {
while (count[i] > 0) { //说明count[i]这里存放了数据出现的次数--》(count[i] 是数据i出现的次数
array[indexArrray] = i+minVal; //一定要加minval,因为不一定就是i出现了count[i]
count[i]--;//拷贝一次之后次数减少一个
indexArrray++;//下标继续向后移动
}
}
}
11.topK问题
求解数组中前k个最小的元素--》大根堆完成
public class topK {
public static int[] topK(int[] array,int k) {
//1.创建一个大小为k的大根堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
//2.遍历数组中,前k个元素放到队列中
for (int i = 0; i < array.length; i++) {
if (maxHeap.size() < k) {
maxHeap.offer(array[i]);//没超过k个元素,就继续往里面放元素
}else {
//3.从第k+1个元素开始,每个元素与堆顶元素进行比较
int top = maxHeap.peek(); //获取当前堆顶元素
if (top > array[i]) { //如果当前元素<栈顶元素 ,
maxHeap.poll(); //弹出堆顶元素
maxHeap.offer(array[i]); //存入堆顶元素
}
}
}
int[] tmp = new int[k];
for (int i = 0; i < k; i++) {
tmp[i] = maxHeap.poll();
}
return tmp;
}
public static void main(String[] args) {
int[] array = {18,21,8,10,34,12};
int[] tmp = topK(array,3);
System.out.println(Arrays.toString(tmp));
}
}
面试题1:查找和最小的 K 对数字
给定两个以 升序排列 的整数数组 nums1和nums2,以及一个整数 k
定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2 。请找到 和最小的 k个数对 (u1,v1), (u2,v2) ... (uk,vk) 。 list类型就可存放一对值
public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
PriorityQueue<List<Integer>> maxHeap = new PriorityQueue<>(k, new Comparator<List<Integer>>() {
@Override
public int compare(List<Integer> o1, List<Integer> o2) {
return (o2.get(0)+o2.get(1))-(o1.get(0)+o1.get(1));
}
});
for (int i = 0; i < Math.min(nums1.length,k); i++) {
for (int j = 0; j < Math.min(nums2.length,k); j++) {
if (maxHeap.size() < k) {
List<Integer> tmpList = new ArrayList<>();
tmpList.add(nums1[i]);
tmpList.add(nums2[j]);
maxHeap.offer(tmpList);
}else {
int top = maxHeap.peek().get(0) + maxHeap.peek().get(1);
if (top > nums1[i]+nums2[j]) {
maxHeap.poll();
List<Integer> tmpList = new ArrayList<>();
tmpList.add(nums1[i]);
tmpList.add(nums2[j]);
maxHeap.offer(tmpList);
}
}
}
}
List<List<Integer>> ret = new ArrayList<>();
for (int i = 0; i < k && !maxHeap.isEmpty();i++) {
ret.add(maxHeap.poll());
}
return ret;
}
11.测试数据运行时间
//========================测试有序数据运行时间==================================================//
public static void testTime1(int capacity) {
int[] array = new int[capacity];
for (int i = 0; i < array.length; i++) {
array[i] = i;
}
long start = System.currentTimeMillis();
insertSort(array);
shellSort(array);
selectSort(array);
long end =System.currentTimeMillis(); //时间单位毫秒
System.out.println(end-start);
}
public static void main0(String[] args) {
testTime1(10_0000); //1745 说明了有序的时间更快
testTime2(10_0000); //5598
}
//========================测试无序数据运行时间==================================================//
public static void testTime2(int capacity) {
int[] array = new int[capacity];
Random random = new Random();
for (int i = 0; i < array.length; i++) {
array[i] = random.nextInt(capacity);
}
long start = System.currentTimeMillis();
insertSort(array);
shellSort(array);
selectSort(array);
quickSort(array);
long end =System.currentTimeMillis(); //时间单位毫秒
System.out.println(end-start);
}
public static void main1(String[] args) {
int[] array = {12,5,18,10,4,2};
int[] array1 = {12,99,18,11,4,2};
// insertSort(array);
// shellSort(array1);
// selectSort(array1);
// heapSort(array);
// bubbleSorts(array1);
quickSort(array);
quickSort(array1);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(array1));
}