数据结构与算法——排序(下)

总结:

我发现排序想要时间复杂度更低,要尽量保证排序的数组要规律有序,插入排序分为有序区和无序区,且无序要有序规律时会自动跳到下个无序,所以很快。

而根据“排序想要时间复杂度更低,要尽量保证排序的数组要规律有序”,可以将数组分成多个数组,排序后再合并排序,这就是归并排序,每次排序两个数组的内里相对有序的,所以会很快

而桶排序也同理,是将数组的数根据值放到多个桶里,桶之间相对规律将整体排序转化为多个桶的排序,将桶里的排序后再将桶合起来的到最终结果。

希尔排序也是同理,按倍数分成多个插排,而倍数位1时就是整体的插入排序,这个过程中每个倍数的插排都是在相对有序的数组上进行的,所以会更快,节省时间。所以当数据大的时候,希尔排序相对于插入排序优势更明显。

这些更快更高级的排序方法会抓住“想要时间复杂度更低,要尽量保证排序的数组要规律有序"的规律,所以基本上都用得到递归

1.希尔排序

希尔排序(Shell Sort)是插入排序的一种,它是针对直接插入排序算法的改进。该方法又称缩小增量排序,因DL.Shell于1959年提出而得名。

希尔排序实质上是一种分组插入方法。

希尔排序的时间复杂度与增量(即,步长gap)的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²),而Hibbard增量的希尔排序的时间复杂度为O(N3/2)。

//希尔排序
#include <iostream>
using namespace std;
void shell (int a[],int length,int n){
	if(length!=0){
		for(int i=1;i<=length;i++){
			
			for(int j=0;j<n/length;j++){
				for(int k=j-1;k>=0;k--){
					if(a[i+k*length]<=a[i+(k+1)*length])break;
					swap(a[i+k*length],a[i+(k+1)*length]);
			   }
			}
			
		}
		shell(a,length/2,n);
    }
}
int main ()
{
	int n;cin >>n;
	int a[n+1];
	for(int i=1;i<=n;i++)cin >>a[i];
	shell (a,n/2,n);
	for(int i=1;i<=n;i++)cout <<a[i] << " ";	
	
	return 0;
 } 

2.计数排序

#include <iostream>
#include <vector>
using namespace std;
int main ()
{int n;cin >> n;
int a[n+1]={0};
int Max=0; 
for(int i=1;i<=n;i++){
	cin>>a[i];
	Max=max(a[i],Max);}
vector<int> b(Max+1,0); 
for(int i=1;i<=n;i++)b[a[i]]++;
for(int i=1;i<=Max;i++){
	while(b[i]>0){
		cout << i << " ";
		b[i]--;
	}	
} 
	returns 0;
 } 

3.桶排序

计数排序的升级版,避免了多余空间的浪费,而且每个桶之间相对有序,对每个桶进行排序再整体整合

#include <iostream>
#include <vector>
using namespace std;
int n;
void tong(int Max,int Min,int a[]){
	std :: vector< std ::vector<int> > vec((Max-Min+1)/10+1);
	for(int i=1;i<=n;i++){
		int index=(a[i]-Min+1)/10;
		vec[index].push_back(a[i]);
	}
	for(int i=0;i<=(Max-Min+1)/10;i++){
		for(int j=0;j<vec[i].size();j++){
			for(int k=j-1;k>=0;k--){
				if(vec[i][k]<=vec[i][k+1])break;
				swap(vec[i][k],vec[i][k+1]);	
		  }
		}
	}
	for(int i=0;i<=(Max-Min+1)/10;i++){
		for(int j=0;j<vec[i].size();j++){
			cout <<vec[i][j] <<" ";
		}
	}		
}
int main ()
{
	cin >>n;
	int a[n+1];
	for(int i=1;i<=n;i++)cin >> a[i];
	int Min=a[1],Max=a[1];
	for(int i=1;i<=n;i++){
		Min=min(a[i],Min);
		Max=max(a[i],Max);
	}
	tong(Max,Min,a);	
	return 0;
}

4.堆排序

二叉树在数组中调用

#include <iostream>
using namespace std;
int jz[32]={1};
void zhuanhuan(int j,int a[],int er){
    if(j*2<=er){
     if(a[j]<a[j*2]&&a[j*2]>=a[j*2+1]){//j*2大
     swap(a[j],a[j*2]);
      zhuanhuan(j*2,a,er);
    }
    else
    if(a[j]<a[j*2+1]&&a[j*2]<=a[j*2+1]){//j*2-1大
    swap(a[j],a[j*2+1]);
     zhuanhuan(j*2+1,a,er);
    }
    }
};
void duipai(int n,int a[],int shu,int er){
   
for(int i=shu-1;i>=0;i--){
    for(int j=jz[i];j<=jz[i]*2-1;j++){
        zhuanhuan(j,a,er);
    }
}
}
int main()
{int n;cin >> n;
int shu=0;
int er=1;
while (er<n)
{er=er*2+1;
shu++;
jz[shu]=jz[shu-1]*2;
}
int a[er+1]={0};
for(int i=1;i<=n;i++)cin >> a[i];
for(int i=shu-1;i>=0;i--){
    for(int j=jz[i];j<=jz[i]*2-1;j++){
        zhuanhuan(j,a,er);
    }
}
for(int i=1;i<=n;i++){
    cout << a[1] << " ";
    a[1]=0;
    swap(a[1],a[n-1+1]);
     zhuanhuan(1,a,er);
}    
    return 0;
}

5.归并排序

时间复杂度:O(n*logn)

将两个的有序数列合并成一个有序数列,我们称之为"归并"。
归并排序(Merge Sort)就是利用归并思想对数列进行排序,每次归并后归并得到的数列是有序的,对下一次归并的时间复杂度更有利(越规律越快)。

#include <iostream>
#include <vector>
using namespace std;
void digui(int a[],int start,int end){
    if(start!=end){
        digui(a,start,(start+end)/2);
        digui(a,(start+end)/2+1,end);
        vector<int> vec;
        for(int j=(start+end)/2+1,i=start;j<=end||i<=(start+end)/2;j++){
                while(a[j]>a[i]&&i<=(start+end)/2)
                {
                vec.push_back(a[i]);
                i++;
                }
                 vec.push_back(a[j]);
                 while(j==end&&i<=(start+end)/2){
                    vec.push_back(a[i]);
                    i++;
                 }   
         }
         for(int i=start;i<=end;i++){
            a[i]=vec[i-start];
         }
    }
}
int main()
{
    int n;cin >> n;
    int a[n+1]={0};
    for(int i=1;i<=n;i++) cin >> a[i];
    digui(a,1,n);
    for(int i=1;i<=n;i++){
           cout << a[i] << " ";
     }
    
    
    return 0;
} 

6.快速排序

类似二分法查找,因为每个数最终排序后再数组中的位置是不变的,所以每次找数对应的位置使“在这之前小于它,在这之后大于它”,也是相对规律。缩短的排序的范围,每个数找到所在范围里的位置后,再分割,直到所有数排完为止。

通俗点就是用二分排序,每次排序后右边所有数大于左边,即是相对有序了,之后再进行快排(二分),直到排完。

#include <iostream>
using namespace std;
void kuaipai(int a[], int l, int r)
{
    if (l < r)
    {
        int i,j,x;
        i = l;
        j = r;
        x = a[i];
        while (i < j)
        {
            while(i < j && a[j] > x)
                j--; // 从右向左找第一个小于x的数
            if(i < j)
                a[i++] = a[j];
            while(i < j && a[i] < x)
                i++; // 从左向右找第一个大于x的数
            if(i < j)
                a[j--] = a[i];
        }
        a[i] = x;
        kuaipai(a, l, i-1); /* 递归调用 */
        kuaipai(a, i+1, r); /* 递归调用 */
    }
}
int main ()
{int n; cin >> n;
int a[n+1];
for(int i=1;i<=n;i++)cin >> a[i];
kuaipai(a,1,n);
for(int i=1;i<=n;i++)cout  << a[i] << " ";





    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值