1.插入排序
基本思想:每一步将一个待排序的数据插入到前面已经排好序的有序序列中,直到插完所有元素为止。
每次选择无序区间的第一个元素,在有序区间选择合适的位置插入。当取第一个元素时认为是有序的,第二次从数组的第二个数据开始往前比较,即一开始用第二个数和他前面的一个比较,如果符合条件(比前面的大或者小),则让它们交换位置。
代码实现
public static void insertSort(int[] array){
for (int i = 1; i < array.length; i++) {
int tmp = array[i]; //每次将i下标值保存在中间变量tmp中
int j = i - 1; //j每次开始的位置在i之前
for (; j >=0; j--) {
if(array[j] > tmp){
array[j+1] = array[j];
}else{
break;
}
}
array[j+1] = tmp;
}
}
2.希尔排序
希尔排序:是插入排序的一种进阶排序算法,通过一个不断缩小的增量序列,对无序序列反复的进行拆分并且对拆分后的序列使用插入排序的一种算法,所以也叫作“缩小增量排序”或者“递减增量排序”。
比如对下面这个数组采取[3,2,1]递减增量序列
第一次增量为3,然后对每个组进行插入排序
第2次增量为2,对每个组进行插入排序
最后一次对整个序列进行插入排序(增量为1)
代码实现
public class TestDemo {
public static void main(String[] args) {
TestDemo q = new TestDemo();
int[] drr = {2,1}; //代表增量数组 增量最大值不能大于数组长度,没有明确的增量确定规律
int[] array = {10,3,2,7,19,78,65,127};
System.out.println("希尔排序前: "+ Arrays.toString(array));
for (int i = 0; i < drr.length; i++) {
q.xiertSort(array,drr[i]);
}
System.out.println("希尔排序后: "+Arrays.toString(array));
}
public void xiertSort(int[] array, int gap){
//这里i++换成i=i+gap也可以
for (int i = gap; i < array.length; i++) {
int tmp = array[i];
int j = i - gap;
for (; j >=0; j-=gap) {
if(array[j] > tmp){
array[j + gap] = array[j];
}else{
break;
}
}
array[j + gap] = tmp;
}
}
3.选择排序
基本思想:每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元素排完。
代码实现
public static void selectSort(int[] array){
for (int i = 0; i < array.length; i++) {
//j每次指向i后面
for (int j = i+1; j < array.length; j++) {
if(array[j] < array[i]){
int tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
}
}
4.快速排序(重要)
基本思想:
1.从待排序区间选择一个数,作为基准值(pivot)
2.划分区间:遍历整个待排序区间,将比基准值小的(可以相等)的元素放到基准值的左区间,将比基准值大的(可以相等)的元素放在基准值的右区间
3.采用分治思想,对左右两个区间按照同样的方式处理,直到小区间的长度为1,代表已经有序,或者小区间长度为0,代表没有数据。
代码实现
public static int pivot(int[] array, int start, int end){
int tmp = array[start]; //将start的值给中间变量tmp
while(start < end){
while(start < end && array[end] > tmp){
end--;
}
//当不满足start<end,即后面元素都比tmp大,end一直走到第一个下标,直接break
if(start >= end){
break;
//因为不满足array[end]>array[start],循环退出,此时把end的值赋值给start
}else{
array[start] = array[end];
}
while(start < end && array[start] < tmp){
start++;
}
if(start >= end){
break;
}else{
array[end] = array[start];
}
}
array[start] = tmp;
return start; //要寻找的基准值
}
public static void quickSort(int[] array, int low, int high){
if(low < high){
int center = pivot(array,low,high);
pivot(array,low,center-1); //对基准值左边分治
pivot(array,center+1,high); //对基准值右边分治
}
}
public static void main(String[] args) {
int[] array = {10,3,2,7,19,78,65,127};
System.out.println("快速排序前: "+ Arrays.toString(array));
quickSort(array,0,array.length-1);
System.out.println("快速排序后: "+Arrays.toString(array));
}
先到这路吧,对于快速排序而言,还有优化问题
//快速排序非递归方法
public static void quickSort1(int[] array){
Stack<Integer> stack = new Stack<>();
int low = 0;
int high = array.length - 1;
int piv = pivot(array,low,high);
if(piv > low+1){
stack.push(low);
stack.push(piv-1);
}
if(piv < high-1){
stack.push(piv+1);
stack.push(high);
}
while(!stack.empty()){
//弹出两个元素,作为新的high和low
high = stack.pop();
low = stack.pop();
piv = pivot(array,low,high);
if(piv > low+1){
stack.push(low);
stack.push(piv-1);
}
if(piv < high-1){
stack.push(piv+1);
stack.push(high);
}
}
//循环退出,栈为空,排序完成
}
5.归并排序(重要)
public static void merge(int[] array, int low, int mid, int high){
//对两个待合并段合并
int s1 = low;
// int e1 = mid;
int s2 = mid+1;
// int e2 = high;
int[] tmp = new int[high-low+1]; //每一次合并后数组大小不一致
int k = 0; //数组tmp下标
while(s1 <= mid && s2 <= high){
if(array[s1] <= array[s2]){
//谁小把谁放在tmp中
//tmp[k++] = array[s1++]也可
tmp[k] = array[s1];
k++; //数组下标往后移
s1++;
}else{
tmp[k] = array[s2];
k++;
s2++;
}
//当s1未走到mid,s2已经到end时
while(s1 <= mid){
tmp[k++] = array[s1++]; //栽倒了
}
//当s2走到end,s1未到mid
while(s2 <= high){
tmp[k++] = array[s2++];
}
for (int i = 0; i < tmp.length; i++) {
array[i + low] = tmp[i];
}
}
}
public static void mergeSort(int[] array, int low,int high){
if(low >= high) return ;
int mid = (high+low)/2;
mergeSort(array,low,mid);
mergeSort(array,mid+1,high);
///合并操作
merge(array, low,mid,high);
}
6.堆排序(重要)
public void createBigHeap(int[] arr){
for (int i = 0; i < arr.length; i++) {
this.elem[i] = arr[i];
this.usedSzie++;
}
//i表示父亲结点,依次调整
for (int i = (this.usedSzie-2)/2; i >= 0 ; i--) {
adjustDown(i, this.usedSzie);
}
}
------------------------------------------------------------
public void adjustDown(int parent, int len){
int child = 2*parent+1;
//len代表数组实际长度
//child小于len说明 parent有左孩子,不能确定是否有右孩子 child==len说明 parent没有左右孩子
while(child < len){
//child+1 < len保证当前父亲结点有右孩子
//当左孩子小于右孩子时,child走到右孩子下标,保证child是左右孩子最大值下标
if(child+1 < len &&this.elem[child] < this.elem[child+1]){
child++;
}
//当孩子结点大于父亲结点时,交换
if(this.elem[child] > this.elem[parent]){
int tmp = this.elem[child];
this.elem[child] = this.elem[parent];
this.elem[parent] = tmp;
parent = child;
child = 2*parent+1;
}else{
//我们是从最后一棵树调整的
//当this.elem[child] <= this.elem[parent]时,表明此时的树是大根堆,后面不需要循环了
break;
}
}
}
-------------------------------------------------------------
public void heapSort(){
int end = this.usedSzie-1; //用end表示数组的尾元素下标,end==0时就不换了
//将队头元素和队尾元素交换
while(end > 0){
int tmp = this.elem[0];
this.elem[0] = this.elem[end];
this.elem[end] = tmp;
adjustDown(0,end); //调整后end需要减1,让它从后往前走,保持数组从后往前是由大到小
end--;
}
}