常见排序算法总结

1、冒泡排序

1)思想

设待排序元素序列中的元素个数为 n。最多作 n-1 趟,i = 1, 2, , n-1 。
在第 i 趟中从后(前)向前(后) ,j = n-1, n-2, , i,顺次两两比较V[j-1]和V[j]。如果发生逆序,则交换V[j-1]和V[j]。
第i趟对待排序元素序列V[i-1],V[i],,V[n-1]进行排序,结果将该序列中排序码最小(大)的元素交换到序列的第一个(最后)位置,其它元素也都向排序的最终位置移动。在个别情形,元素可能在排序中途向相反的方向移动。

2)自己的代码实现

	public static void bubblesort(int[] arr)
	{
		int n=arr.length;
		for(int i=0;i<n-1;i++)
		{
			for(int j=0;j<n-i-1;j++)
			{
				if(arr[j]>arr[j+1])
				{
					int temp=arr[j];
					arr[j]=arr[j+1];
					arr[j+1]=temp;
				}
			}
		}
	}

2、直接插入排序

1)思想

插入第i (i≥1) 个元素时,前面的V[0], V[1], …, V[i-1]已经排好序。这时,用V[i]的排序码与V[i-1], V[i-2], … 的排序码顺序进行比较,直到找到插入位置即将V[i]插入,原来位置上的元素向后顺移。

2)自己的代码实现

(最好画个图便于自己理解)

	public static void insertsort(int[] arr)
	{
		int n=arr.length;
		int i=0,j=0;
		for(i=1;i<n;i++)
		{
			for(j=i-1;j>=0;--j)
			{
				if(arr[i]>arr[j])break;//j+1即arr[i]需插入的位置
			}
			int k=i,temp=arr[i];//要把arr[i]先保存下来
			while(k>j+1)
			{
				arr[k]=arr[k-1];
				k--;
			}
			arr[j+1]=temp;
			
		}
	}

3、快速排序

1)思想

快速排序

快速排序 的原理及其java实现(递归与非递归)

2)自己的代码实现

递归:

public static void quicksort(int start,int end,int[] arr){
		if(start>=end)return ;
        int X=arr[start];
        //如果要改成中间位置,只需把arr[mid]与arr[start]交换位置

        int i=start,j=end;
        while(i<j){
            while(arr[j]>=X&&i<j)j--;
            if(i<j)arr[i++]=arr[j];//填坑,j为新坑

            while(arr[i]<X&&i<j)i++;
            if(i<j)arr[j--]=arr[i];//填坑,i为新坑
        }
        arr[i]=X;

        quicksort(start,i-1,arr);
        quicksort(i+1,end,arr);
	}

非递归:

public static void quicksort2(int start,int end,int[] arr){//非递归
		Stack<Integer> s=new Stack<Integer>();
		
		s.push(start);
		s.push(end);
		
		while(!s.empty()){
			end=s.pop();
			start=s.pop();
			
			//partition
			
			int X=arr[start];
			
	        int i=start,j=end;
	        while(i<j){
	            while(arr[j]>=X&&i<j)j--;
	            if(i<j)arr[i++]=arr[j];//填坑,j为新坑

	            while(arr[i]<X&&i<j)i++;
	            if(i<j)arr[j--]=arr[i];//填坑,i为新坑
	        }
	        arr[i]=X;
	        
	        //以上为partition操作
	        
	        int index=i;
	        if(start<index-1){
	        	s.push(start);
	        	s.push(index-1);//一定-1
	        }
	        if(end>index+1){
	        	s.push(index+1);//一定+1
	        	s.push(end);
	        }
			
		}


	}

4、归并排序

1)思想

将待排序的元素序列划分为两个长度大致相等的子序列;
分别对每个子序列递归排序;
最后将两个排好序的子序列合并成一个有序序列,即归并过程(称为两路归并(2-way merging))。

2)自己的代码实现


    int[] temp;
    public void merge(int[] nums,int start,int mid,int end){
        int i=start,j=mid+1;
        int index=start;
        while(i<=mid&&j<=end){
            if(nums[i]<=nums[j]){temp[index++]=nums[i];i++;}
            else {temp[index++]=nums[j];j++;}
        }
        while(i<=mid){temp[index++]=nums[i];i++;}
        while(j<=end){temp[index++]=nums[j];j++;}

        for(i=start;i<=end;i++)nums[i]=temp[i];        
    }
    public void mergeSort(int[] nums,int start,int end){
        if(start>=end)return;
        int mid=(start+end)/2;
        mergeSort(nums,start,mid);
        mergeSort(nums,mid+1,end);
        merge(nums,start,mid,end);
    }

5、堆排序

1)思想

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2)自己的代码实现

public class TestHeap {
	public static void main(String[] args) {
		//PriorityQueue<Integer> pq=new PriorityQueue<Integer>((o1,o2)->o1-o2);
		int[] arr= new int[]{1,3,4,2,6,8,5,7};
		System.out.println("排序前:");
		for(int i=0;i<arr.length;i++)System.out.print(arr[i]+",");
		MyHeap h=new MyHeap(arr);
		int[] res=new int[arr.length];
		for(int i=0;i<arr.length;i++) {
			res[i]=h.remove();
			
		}
		System.out.println("\n排序后:");
		for(int i=0;i<arr.length;i++)System.out.print(res[i]+",");
	}
}
class MyHeap{
	private int[] data;
	private int cursize;
	public MyHeap(int[] data) {
		this.data=new int[data.length];
		System.arraycopy(data, 0, this.data, 0, data.length);
		cursize=data.length;
		int curIndex=(cursize-2)/2;//最后一个分支结点
		//2*curIndex+2=cursize-1(cursize为奇数,最后一个结点为右结点)
		//如cursize=3,curIndex=0
		
		//2*curIndex+1=cursize-1(cursize为偶数,最后一个结点为左结点)
		//如cursize=4,curIndex=1
		while(curIndex>=0) {
			siftDown(curIndex,cursize-1);
			curIndex--;
		}
		
	}
	
	public void siftDown(int start,int end) {
		//如果子女的值小于父结点的值,  则关键码小的上浮, 
		//继续向下层比较, 将一个集合局部调整为最小堆。
		int parentIndex=start,sonIndex=parentIndex*2+1;//为左结点
		while(sonIndex<=end) {
			if(sonIndex<end&&data[sonIndex]>data[sonIndex+1])sonIndex++;//让sonIndex指向两个子数中较小的
			
			if(data[sonIndex]<data[parentIndex]) {
				int temp=data[parentIndex];data[parentIndex]=data[sonIndex];data[sonIndex]=temp;
			}
			
			parentIndex=sonIndex;
			sonIndex=parentIndex*2+1;
		}
		
	}
	
	public int remove() {

		int x=data[0];
		
		data[0]=data[cursize-1];
		
		cursize--;
		
		siftDown(0, cursize-1);
		
		return x;
		
	}
	
	
	
}

6、希尔排序

1)思想

设待排序元素序列有 n 个元素,首先取一个整数 gap < n 作为间隔(增量),将全部元素分为 gap 个子序列,所有距离为 gap 的元素放在同一个子序列中,在每一个子序列中分别施行直接插入排序。
然后缩小间隔gap,例如取 gap = gap/2(取上界),重复上述的子序列划分和排序工作。直到最后取 gap = 1(此时序列“基本有序”),将所有元素放在同一个序列中排序为止
子序列插入排序

2)自己的代码实现

public static void shellSort(int start,int end,int[] arr){//希尔排序
		int gap=arr.length/2;
		int i=0,j=0;
		while(gap>=1){//内部插入排序
			for(int p=start;p<=end-gap;p++){
				
				for(i=p+gap;i<arr.length;i+=gap)
				{
					for(j=i-gap;j>=0;j-=gap)
					{
						if(arr[i]>arr[j])break;//j+gap即arr[i]需插入的位置
					}
					int k=i,temp=arr[i];//要把arr[i]先保存下来
					while(k>j+gap)
					{
						arr[k]=arr[k-gap];
						k-=gap;
					}
					arr[j+gap]=temp;
					
				}			
			}
			
			gap=gap/2;

		}
	}

7、选择排序

1)思想

1)在元素 V[i]~V[n-1] 中选择具有最小排序码的元素;
2)若它不是这组元素中的第一个元素,则将它与这组元素中的第一个元素对调;
3)在这组元素中剔除这个具有最小排序码的元素,在剩下的元素V[i+1]~V[n-1]中重复执行第1)、2)步,直到剩余元素只有一个为止。

2)自己的代码实现

public static void selecrSort(int start,int end,int[] arr){
		int minIndex=0;
		for(int i=start;i<=end;i++){
			minIndex=i;
			for(int j=i+1;j<=end;j++){
				if(arr[j]<arr[minIndex])minIndex=j;
			}
			if(minIndex!=i){
				int temp=arr[i];
				arr[i]=arr[minIndex];
				arr[minIndex]=temp;
			}
		}
	}

8、计数排序

1)思想

计数排序

2)自己的代码实现

public static void jishu(int[] arr){
		int max= Integer.MIN_VALUE,min=Integer.MAX_VALUE;
		for(int i:arr){
			if(i<min)min=i;
			if(i>max)max=i;
		}
		int[] jishu=new int[max-min+1];
		for(int i:arr){
			jishu[i-min]++;
		}
		
		int index=0;
		for(int i=0;i<jishu.length;i++){
			while(jishu[i]-->0)arr[index++]=min+i;
		}
	}

9、桶排序

1)思想

桶排序

2)自己的代码实现

public static void tong(int[] arr,int number){//number即每个桶中的平均数量
		int max= Integer.MIN_VALUE,min=Integer.MAX_VALUE;
		for(int i:arr){
			if(i<min)min=i;
			if(i>max)max=i;
		}
		
		int length=(max-min)/number+1;
		ArrayList[] tong=new ArrayList[length];
		
		for(int i=0;i<tong.length;i++){
			tong[i]=new ArrayList<Integer>();
		}
		
		for(int i:arr){
			tong[(i-min)/number].add(i);//加到相应的桶中去
		}
		
		
		int index=0;
		for(int i=0;i<tong.length;i++){
			Collections.sort(tong[i]);//桶内排序
			for(int j=0;j<tong[i].size();j++)arr[index++]=(int) tong[i].get(j);
		}
	}

补充

1)时间复杂度:可以理解为代码执行的次数
比如二分法,一个长度为n的数组,用二分法查找,查找的次数就是时间复杂度
设次数为k,则2的k次方=n, k=log2 n(底数为2)
则时间复杂度为O(logn)

2)Arrays.sort()

深入理解Arrays.sort()

较小用插入,较大用归并,其他用快排

3)稳定排序
稳定排序

题目

以下题目为大二上学期数据结构老师在PPT上放的思考题,答案为我自己的答案,不一定准确

1)如何对n个数进行排序,要求时间复杂度O(n),空间复杂度O(1)

答:计数排序

2)若有1T的数据,需要实现由大到小排序,你用什么办法,说说你的思路和想法?

答:每次读512M,内部排序,然后写到小文件里,之后再把这些小文件归并

3)若有10G的数据,如果两条数据一样,则表示该两条数据重复了,现在给你512M的内存,把这10G中重复次数最高的10条数据取出来。

答:

①先读进来第一个512M的数据,用hashmap记录每个数据重复的次数,

Map<Integer,Integer> map=HashMap<>();
if(map.containsKey(数据))map.put(数据,map.get(数据)+1);
else map.put(数据,1);

②然后读进来第二个,第一个中出现过的数据,就把它的次数+1,没出现过的写到一个temp.txt文件中
③重复第②步,依次把20个部分都读一遍,最后HashMap中存的就是20个部分中都出现过的数据,把它们桶排序,输出到result1.txt中
④之后再处理temp.txt中的数据

  • 若它的大小小于等于 512M,则直接HashMap+桶排序,将结果输出到result2.txt里;
  • 若它的大小大于512M,则继续分成多个部分,每次读512M,重复①②③,得到temp2.txt,temp3.txt等,以及result2.txt,result3.txt等

⑤如果有temp2.txt,temp3.txt之类的,重复第④步
⑥最后得到的result1.txt,result2.txt等,它们中的数据肯定是互相不重复的,且各自进行了桶排序,把重复次数最多的放在了最前面,所以接下来只需把每个文件中重复次数最多的前十个数据读进来,进行桶排序,即可得到所有数据中重复次数最多的十个数据

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值