数据结构 -- 十大排序算法

在这里插入图片描述1. 冒泡排序

①、算法描述:

  • 比较相邻的元素。如果第一个比第二个大,就交换它们两个;
  • 对每一对相邻元素做同样的工作,第一轮使尾部值最大,第二轮尾部两个值最大。
  • 针对所有的元素重复以上的步骤;

②、代码实现:

	public static void bubbleSort(int[] list) {
		boolean needswap = true;
		for(int i = 1; i < list.length && needswap; i++){
			needswap = false;
			for(int j = 0; j < list.length - i; j++){
				if(list[j] > list[j + 1]){
					int tmp = list[j];
					list[j] = list[j + 1];
					list[j + 1] = tmp;
					needswap = true;
				}
			}
		}
	}

2、选择排序(Selection Sort)

①、算法描述:
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾(即与未排序序列的第一个交换)。以此类推,直到所有元素均排序完毕。

②、代码实现

	public static void selectSort(int[] list) {
		if(list.length == 0) return;
		for(int i = 0; i < list.length; i++) {
			int maxIndex = i;
			for(int j = i; j < list.length; j++) {
				if(list[j] < list[maxIndex]) {
					maxIndex = j;
				}
			}
			int tmp = list[maxIndex];
			list[maxIndex] = list[i];
			list[i] = tmp;
		}		
	}

3. 插入排序

①、算法描述:

  • 从第一个元素开始,该元素可以认为已经被排序;
  • 取出下一个元素,在已经排序的元素序列中从后向前扫描;
  • 如果该元素(已排序)大于新元素,将该元素移到下一位置;
  • 重复步骤3,直到已排序元素小于/等于新元素的位置;将新元素插入到该位置;
  • 重复步骤2~5。

②、代码实现

public void insertSort(int[] list){
	for(int i = 1; i < list.length; i++){
	int pos = list[i];
	int index = i - 1;
	while(index >= 0 && list[index] > pos){
		list[index + 1] = list[index];
		index--;
	}
	list[index + 1] = pos;
	}
}

4、希尔排序(Shell Sort)

①、算法描述:

  • 选择一个增量序列, eg: 4, 2, 1;

  • 每趟排序,根据对应的增量,将待排序列分割成若干长度的子序列,分别对各子表进行直接插入排序。

    ②、代码实现:

public void shellSort(int[] array){
	int len = array.length;
	int gap = len / 2;
	while(gap > 0){
		for(int i = gap; i < len; i++){
			int tmp = array[i];
			int index = i - gap;
			while(index >= 0 && array[index] > tmp){
				array[index + gap] = array[index];
				index -= gap;
			}
			array[index + gap] = tmp;
		}
		gap /= 2;
	}
}

5、归并排序(Merge Sort)

①、算法描述:

  • 把长度为n的输入序列分成两个长度为n/2的子序列;
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。

②、代码实现

	private int[] tmp ;
	public static void mergeSort(int[] list) {
		tmp = new int[list.length];
		mergeSort(list, 0, list.length-1);
	}
    public static void mergeSort(int[] a,int start,int end){
	        if(start < end){//当子序列中只有一个元素时结束递归
	             int mid = (start + end)/2;
	             mergeSort(a, start, mid);
	             mergeSort(a, mid + 1, end);
	             merge(a, start, mid, end);//合并
	        }
	    }
	  
    public static void merge(int[] a,int left,int mid,int right){
        int p1 = left, p2 = mid + 1, k = left;//p1、p2是检测指针,k是存放指针
        while(p1 <= mid || p2 <= right){
        	if(p1 > mid)
        		tmp[k++] = a[p2++];
        	else if(p2 > right)
        		tmp[k++] = a[p1++];
        	else if(a[p1] <= a[p2])
               		tmp[k++] = a[p1++];
                else
                	tmp[k++] = a[p2++];
        }

        for (int i = left; i <= right; i++) 
              a[i] = tmp[i];
    }

6、快速排序(Quick Sort)

①、算法描述:

  • 从数列中挑出一个元素,称为 “基准”(pivot);
  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面。
  • 递归地把小于基准值元素的子数列和大于基准值元素的子数列排序。

②、代码实现:递归

public void quickSort(int[] list, int start, int end){
	if(start > end) return;
	int index = partition(list, start, end);
	quickSort(list, start, index - 1);
	quickSort(list, index + 1, end);
}

public int partition(int[] List, int start, int end){
	int pivot = list[start];
	int i = start, j = end;
	while(i < j){
		while(i < j && list[j] >= pivot)  j--;
		list[i] = list[j];
		while(i <j && list[i] < pivot)  i++;
		list[j] = list[i];
	}
	list[i] = pivot;
	return i;
}

非递归实现:

public void quickSort(int[] array,int start, int end){
	Stack<Integer> stack = new Stack<>();
	stack.push(start);
	stack.push(end);

	while(!stack.isEmpty()){
		int right = stack.pop();
		int left = stack.pop();
		int index = partition(array, left, right);

		if(index - 1 > left){
			stack.push(left);
			stack.push(index - 1);
		}

		if(index +1 < right){
			stack.push(index +1);
			stack.push(right);
		}
	}
}

7、堆排序:堆排序的时间复杂度是O(N*lgN)。
堆排序构建堆的时间复杂度是N, 重调堆的时间复杂度是logN
堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。

用数组实现二叉堆有如下性质:
性质一:索引为i的左孩子的索引是 (2i+1);
性质二:索引为i的左孩子的索引是 (2
i+2);
性质三:索引为i的父结点的索引是 floor((i-1)/2);

①、算法描述:

  • 将无需序列构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
  • 将其与末尾元素进行交换,此时末尾就为最大值。
  • 然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。
  • 如此反复执行,便能得到一个有序序列了。

②、代码实现:

public void heapSort(int[] arr){
    if(arr == null || arr.length == 0) return;
	for(int i = arr.length / 2 - 1; i >= 0; i--){
		adjustHeap(arr, i, arr.length - 1);
	}

	for(int j = arr.length - 1; j > 0; j--){
		swap(arr, 0, j);
		adjustHeap(arr, 0, j - 1);
	}
}

public void adjustHeap(int[] arr, int start, int end){
     int tmp = arr[start];                    // 当前(current)节点的大小
     for (int k = 2*start + 1; k <= end; k = 2 * k + 1){
        if (k < end && arr[k] < arr[k + 1])
            	k++;                          // 左右两孩子中选择较大者
        if (tmp >= arr[k])  break;        // 调整结束
        else{                             // 交换值
            	arr[start] = a[k];
            	arr[k] = tmp;
        }
		start = k;
    }
}

8、计数排序(Counting Sort):适用于数据比较密集的情况

①、算法描述:

  • 根据待排序集合中最大元素和最小元素的差值范围,申请额外空间;
  • 遍历集合,将每个元素出现的次数记录到对应的额外空间内(index=元素值-min);
  • 填充目标数组:因额外空间存放这每个元素的次数,每填充一个,将对应次数减一

②、代码实现:

public int[]  countSort(int[] array){
	if(array.length == 0) return array;
	int max = array[0], min = array[0];
	for(int i = 1; i < array.length; i++){
		if(array[i] > max)
			max = array[i];
		if(array[i] < min)
			min = array[i];
	}

	int[]  bucket = new int[max - min + 1];
	for(int i = 0; i <array.length; i++)
		bucket[array[i] - min]++;
	int index = 0, i = 0;
	while(index < array.length){
		if(bucket[i] != 0){
			array[index++] = i + min;
			bucket[i]--;
		}else
			i++;
	}
	return array;
}

9、桶排序(Bucket Sort)

①、算法描述:

  • 设置一个定量的数组当作空桶;
  • 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  • 对每个不是空的桶进行排序;
  • 从不是空的桶里把排好序的数据拼接起来。

②、代码实现:

public static void bucketSort(int[] arr){
    
    int max = Integer.MIN_VALUE;
    int min = Integer.MAX_VALUE;
    for(int i = 0; i < arr.length; i++){
        max = Math.max(max, arr[i]);
        min = Math.min(min, arr[i]);
    }    

    int bucketNum = (max - min) / arr.length + 1;   //桶数
    ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
    for(int i = 0; i < bucketNum; i++){
        bucketArr.add(new ArrayList<Integer>());
    }

	for(int i = 0; i < arr.length; i++){            //将元素入桶
		int index = (arr[i] - min) / arr.length;
		bucket.get(index).add(arr[i]);
	}

	for(int i = 0; i < bucket.length; i++){           //对各个桶排序
		Collection.sort(bucket[i]);
	}
}

10、基数排序(Radix Sort)

①、算法描述:

  • 取得数组中的最大数,并取得位数;
  • arr为原始数组,从最低位开始按照每一位的大小进行排序;
  • 常常利用桶排序,每一轮生成10个桶,位数大小对应桶的位置

②、代码实现:

public static int[] RadixSort(int[] array) {
    if (array == null || array.length < 2)
		return array;
	int max = array[0];
	for(int i = 1; i <array.length; i++)
		max = Math.max(max, array[i]);

	int cnt = 0;
	while(max != 0){
		max /= 10;
		cnt++;
	}

	int mod = 10, div = 1;
	ArrayList<ArrayList<Integer>> bucket = new 			
	ArrayList<ArrayList<Integer>>();
	for (int i = 0; i < 10; i++)
       bucket.add(new ArrayList<Integer>());

	for(int i = 0; i < cnt; i++){
		for(int j = 0; j < array.length; j++){
			int num = (array[j] % mod) / div;
			bucket.get(num).add(array[i]);
		}
		int index = 0;
		
		for(int j = 0; j < bucket.size(); j++){
			for(int k = 0; k < bucket.get(j).size(); k++){
				array[index++] = bucket.get(j).get(k);
			}
			bucket.get(j).clear();
		}
		
		mod *= 10;
		div *= 10;
	}
	return array;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值