数据结构--排序算法

1、冒泡排序
比较相邻元素,将小的元素交换到前面,时间复杂度为O(n2),空间复杂度O(1),稳定排序。

void bubbleSort(int [] nums)
{
	if(nums == null || nums.length < 2)
		return;
	for(int i = 0; i < nums.length -1; i++)
	{
		for(int j = 0; j < nums.length - i - 1; j++)
		{
			if(nums[j] < nums[j + 1])
			{
				int temp = nums[j];
				nums[j] = nums[j + 1];
				nums[j + 1] = temp;
			}
		}
	}
}

2、选择排序
从待排序序列中选出最小元素,与待排序序列初始位置的元素进行交换,重复操作直到待排序元素个数为0,时间复杂度为O(n2),空间复杂度O(1),不稳定排序。

void selectionSort(int [] nums)
{
	if(nums == null || nums.length < 2)
		return;
	for(int i = 0; i <  nums.length; i++)
	{
		int min = nums[i];
		int k = i;
		for(int j = i + 1; j < nums.length; j++)
		{
			if(nums[j] < min)
			{
				min = nums[j];
				k = j;
			}
		}
		nums[k] = nums[i];
		nums[i] = min;
	}
}

3、插入排序
将待排序元素逐个插入到已排序序列中。
最坏时间复杂度为O(n2),最好时间复杂度为O(n),平均时间复杂度为O(n2),空间复杂度O(1),稳定排序。

void insertSort(int [] nums)
{
	if(nums == null || nums.length < 2)
		return;
	for(int i = 1; i < nums.length; i++)
	{
		int j = i - 1;
		int temp = nums[i];
		while(j >= 0 && nums[j] > temp)
		{
			nums[j + 1] = nums[j];
			j--; 
		}
		nums[j + 1] = temp;
	}
}

4、快速排序
实际应用中快速排序是表现最好的算法。
快速排序选取基准数,定义左右指针,先移动右指针,当右指针指向的元素比基准数小时停下,再移动左指针,当左指针指向的元素比基准数大时停下,交换左右指针指向的数,重复上述操作,直到左右指针相遇,交换基准数与指针相遇位置的数,再对基准数的左右部分执行相同的排序操作。
快速排序是不稳定的,最好情况时间复杂度为O(nlogn),最坏情况时间复杂度为O(n2),平均时间复杂度为O(nlogn),空间复杂度O(logn)

void quickSort(int [] nums, int left, int right)
{
	if(left >= right)
		return;
	int i = left;
	int j = right;
	int key = nums[left];
	while(i < j)
	{
		while(i< j && nums[j] > key)
			j--;
		while(i < j && nums[i] <= key)
			i++;
		if(i < j)
		{
			int temp = nums[i];
			nums[i] = nums[j];
			nums[j] = temp;
		}
	}
	nums[left] = nums[i];
	nums[i] = key;

	quickSort(nums, left, i - 1);
	quickSort(nums, i + 1, right);
}

5、堆排序
利用堆实现的选择排序,将堆看成完全二叉树。
最大堆要求节点的元素都要不小于其孩子,最小堆要求节点元素都不大于其左右孩子。
堆排序先调用buildMaxHeap将数组改造为最大堆,然后将堆顶和堆底元素交换,之后将底部上升,然后重新调用maxHeapify(堆有序化)保持最大堆性质。
时间复杂度为O(nlogn),空间复杂度O(1),不稳定排序。

void heapSort(int [] nums)
{
	if(nums == null || nums.length < 2)
		return;
		
	int len = nums.length;
	
	buildMaxHeap(nums, len);
	
	for(int i = len - 1; i > 0; i--)
	{
		swap(nums, 0, i);
		len--;
		maxHeapify(nums, 0, len);
	}
}
	
private void buildMaxHeap(int [] nums, int len)
{
	for(int i = (int) (len / 2) ; i >= 0; i--)
	{
		maxHeapify(nums, i, len);
	}
}
	
private void maxHeapify(int [] nums, int i, int len)
{
	int left = 2 * i + 1;
	int right = 2 * i + 2;
	int largest = i;
	
	if(left < len && nums[left] > nums[largest])
	{
		largest = left;
	}
	
	if(right < len && nums[right] > nums[largest])
	{
		largest = right;
	}
	
	if(largest != i)
	{
		swap(nums, i, largest);
		maxHeapify(nums, largest, len);
	}
}
	
private void swap(int [] nums, int i, int largest)
{
	int temp = nums[i];
	nums[i] = nums[largest];
	nums[largest] = temp;
}

6、希尔排序
插入排序高效的实现,将待排序列分为若干子序列,分别进行插入排序,整个序列基本有序时再对进行一次直接插入排序。子序列不是简单的逐段分割,而是彼此相隔某个增量。
没有快速排序快,但是比时间复杂度为O(n2)的算法快,空间复杂度O(1),不稳定排序。

void shellSort(int [] nums)
{
	if(nums == null || nums.length < 2)
		return;
	int len = nums.length;
	int gap = 1;
	while(gap < len)
	{
		gap = gap * 3  + 1;
	}
	while(gap > 0)
	{
		for(int i = gap; i < len; i++)
		{
			int j = i - gap;
			int temp = nums[i];
			while(j >= 0 && nums[j] > temp)
			{
				nums[j + gap] = nums[j];
				j -= gap;
			}
			nums[j + gap] = temp;
		}
		gap = (int)(gap / 3);
	}
}

7、归并排序
递归分治,先把问题划分为子问题,然后合并结果,时间复杂度为O(nlogn),空间复杂度O(n),稳定排序。

void mergeSort(int [] nums, int left, int right)
	{
		if(left >= right)
			return;
		int mid = (left + right) / 2;
		
		mergeSort(nums, left, mid);
		mergeSort(nums, mid + 1, right);
		
		merge(nums, left, mid + 1, right);
	}
	
	private void merge(int [] nums, int left, int mid, int right)
	{
		int [] lArr = new int[mid - left];
		int [] rArr = new int[right - mid + 1];
		for(int i = left; i < mid; i++)
		{
			lArr[i - left] = nums[i];
		}
		for(int i = mid; i <= right; i++)
		{
			rArr[i - mid] = nums[i];
		}
		int i = lArr.length - 1;
		int j = rArr.length - 1;
		int k = right;
		while(i >= 0 && j >= 0)
		{
			if(lArr[i] > rArr[j])
			{
				nums[k--] = lArr[i--];
			}
			else
			{
				nums[k--] = rArr[j--];
			}
		}
		while(i >= 0)
		{
			nums[k--] = lArr[i--];
		}
		while(j >= 0)
		{
			nums[k--] = rArr[j--];
		}
	}

8、计数排序
基本思想是把待排序的数减去最小数作为数组的下标,统计每个数的个数,然后依次输出。需要较多的辅助空间,要求数在一定的范围内,时间复杂度为O(n)。

void countSort(int [] nums)
{
	if(nums == null || nums.length < 2)
		return;
	int min = Integer.MIN_VALUE;
	int max = Integer.MAX_VALUE;
	for(int i = 0; i < nums.length; i++)
	{
		min = Math.min(nums[i], min);
		max = Math.max(nums[i], max);
	}
	
	int [] helper = new int[max - min + 1];
	for(int i = 0; i < nums.length; i++)
	{
		helper[nums[i] - min]++;
	} 

	int index = 0;
	for(int i = 0; i < helper.length; i++)
	{
		while(helper[i] > 0)
		{
			nums[index++] = i + min;
			helper[i]--;
		}
	}
}

9、桶排序
基本思想是把数据放到n个桶内,对桶内数据进行排序,遍历桶依次取出桶中元素。

void bucketSort(int [] nums)
{
	if(nums == null || nums.length < 2)
		return;
	int min = Integer.MIN_VALUE;
	int max = Integer.MAX_VALUE;
	for(int i = 0; i < nums.length; i++)
	{
		min = Math.min(min, nums[i]);
		max = Math.max(max, nums[i]);
	}

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

	for(int i = 0; i < nums.length; i++)
	{
		int num = (nums[i] - min) / nums.length;
		bucket.get(num).add(nums[i]);
	}

	for(int i = 0; i < bucket.size(); i++)
	{
		Collections.sort(bucket.get(i));
	}

	int index = 0;
	for(int i = 0; i < bucket.size(); i++)
	{
		for(int j = 0; j < bucket.get(i).size(); j++)
		{
			nums[index++] = bucket.get(i).get(j);
		}
	}
}

10、基数排序
利用多关键字对单逻辑关键字排序。

11、二分插入排序
跟二分查找时间复杂度相同,时间复杂度最好为O(nlogn),最差为O(n2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值