zoukankan      html  css  js  c++  java
  • 【数据结构】排序

    数据表(dataList):待排元素的集合。

    排序码(key):排序的关键字。

    排序的稳定性:若相等的两个元素经过排序后顺序仍不变则称排序算法是稳定的。

    一个b站学习视频

    一、快速排序

    (一)原理
    选择一个元素作为基准元素,将小于基准元素的都放在其左边,将大于基准元素的都放在其右边。这样序列就被划分为大于和小于基准元素的两部分。对这两部分分别递归处理。基准元素随意选。
    (二)代码

    //快速排序---我自己的板子
    #include<iostream>
    #include<cstdio>
    #define N 100009
    using namespace std;
    
    int n;
    int a[N];
    
    void qsort(int l,int r)
    {
    	int mid=a[(l+r)>>1];
    	int i=l,j=r;
    	do{
    		while(a[i]<mid) i++;
    		while(a[j]>mid) j--;
    		if(i<=j)
    		{
    			swap(a[i],a[j]);
    			i++;
    			j--;
    		}
    	}while(i<=j);
    	if(l<j) qsort(l,j);
    	if(i<r) qsort(i,r);
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	qsort(1,n);
    	for(int i=1;i<=n;i++) printf("%d ",a[i]); 
    	return 0;
    }     
    
    
    //课本上的代码...考试用
    #include"dataList.h"
    template<class T>
    void QuickSort(dataList<T>&L,const int left,const int right)
    {
    	if(left<right)
    	{
    		int pivotpos=L.Partition(left,right);
    		QuickSort(L,left,pivotpos-1);
    		QuickSort(L,pivotpos+1,right);
    	}
    } 
    
    template<class T>
    int dataList<T>::Partition(const int low,const int high)
    {
    	int pivotpos=low;Element<T>pivot=Vector[low];
    	for(int i=low+1;i<=high;i++)
    	{
    		if(Vector[i]<pivot)
    		{
    			pivotpos++;
    			if(pivotpos!=i) swap(Vector[pivotpos],Vector[i]);   //小于基准元素的交换到左侧 
    		}
    	}
    	Vector[low]=Vector[pivotpos];	Vector[pivotpos]=pivot;
    	return pivotpos;                                               //返回基准元素的位置 
    };
     
    

    (三)时间复杂度分析
    O(nlogn)

    二、堆排序

    (一)原理:小根堆保证父亲小于两个儿子,大根堆保证父亲大于两个儿子。
    (二)代码

    //堆排 
    #include<iostream>
    #include<cstdio>
    #define N 1000009
    using namespace std;
    
    int n,tot;
    int d[N];
    
    void up(int x)
    {
    	if(x==0) return;
    	if(d[x]<d[x/2])
    	{
    		swap(d[x],d[x/2]);
    		up(x/2);
    	}
    }
    
    void down(int x)
    {
    	int nxt;
    	if(x*2>tot) return;
    	if(x*2+1>tot) nxt=x*2;
    	else nxt=d[x*2]<d[x*2+1]?x*2:x*2+1;
    	if(d[x]>d[nxt])
    	{
    		swap(d[x],d[nxt]);
    		down(nxt);
    	}
    }
     
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		int x;
    		scanf("%d",&x);
    		d[++tot]=x;
    		up(tot);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		cout<<d[1]<<" ";
    		d[1]=d[tot--];
    		down(1); 
    	}	
    }
    
    
    #define DefaultSize 10;
    template<class T>
    struct Element
    {
    	T key;
    	field otherdata;
    	Element<T>& operator = (Element<T>&x)
    	{
    		key=x.key;
    		otherdata=x.otherdata;
    	}
    	bool operator >= (Element<T>&x){return key>=x.key;}
    	bool operator < (Element<T>&x){return key<x.key;}
    };
    
    template<class T>
    class MaxHeap{
    	public:
    		MaxHeap(int sz=DefaultSize);//构造函数,建立空堆
    		MaxHeap(Element<T>arr[],int n);//构造函数
    		~Maxheap(delete []heap;)//析构函数
    		bool Insert(Element<T>&x);//将x插入到最大堆中
    		bool Remove(Element<T>&x);//删除堆顶上的最大元素
    		bool IsEmpty() const{return currentSize==0;}
    		bool IsFull() const{return currentSize==maxHeapSize;}
    	private:
    		Element<T>*heap;
    		int currentSize;
    		int maxHeapSize;
    		void siftDown(int start,int m);//从start到m自顶向下调整
    		void siftUp(int start);         //从start到0自底向上调整
    		Swap(const int i,const int j)
    		{
    			Element<T>tmp=heap[i];
    			heap[i]=heap[j];
    			heap[j]=tmp;
    	    }
    };
    
    template<class T>
    void maxHeap<T>::siftDown(const int start,const int m)
    {
    	int i=start;int j=2*i+1;
    	Element<T,E>temp=heap[i];//暂存子树根节点
    	while(j<=m)                   //检查是否到最后 
    	{
    		if(j<m&&heap[j]<heap[j+1]) j++;//让child指向两子女的最大者
    		if(temp>=heap[j]) break;
    		else{
    			heap[i]=heap[j];
    			i=j;j=2*j+1;
    		} 
    	} 
    	heap[i]=temp;
    };
    #include"maxheap.h"
    template<class T>
    void HeapSort(maxHeap<T>&H)
    {
    	for(int i=(currentSize-2)/2;i>=0;i--) siftDown(i,currentSize-1);
    	//将表转换成堆
    	for(int i=currentSize-1;i>=0;i--)
    	{
    		Swap(0,i);siftDown(0,i-1);
    	} 
    };
    
    

    (三)时间复杂度
    O(nlogn)

    三、希尔排序

    (一)原理:将数组下标相差gap的元素进行插入排序,然后不断缩小gap。
    (二)代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define N 100009
    using namespace std;
    
    int n;
    int a[N]; 
    
    void ShellSort()
    {
    	int j,temp,d;
    	d=n/2;
    	while(d>0)
    	{
    		for(int i=d+1;i<=n;i++)
    		{
    			temp=a[i];
    			j=i-d;
    			while(j>0&&a[j]>temp)
    			{
    				a[j+d]=a[j];
    				j=j-d;
    			}
    			a[j+d]=temp;
    		}
    		d/=2;
    	}
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    	}
    	ShellSort();
    	for(int i=1;i<=n;i++)
    	{
    		printf("%d ",a[i]);
    	}
    	return 0;
    } 
    
    
    #include"dataList.h"
    template<class T>
    void Shellsort(dataList<T>&L,const int left,const int right)
    {
    	int i,j,gap=right-left+1;
    	Element<T>temp;
    	do{
    		gap=gap/3+1;
    		for(i=left+gap;i<=right;i++)
    		{
    			if(L[i]<L[i-gap])
    			{
    				temp=L[i];j=i-gap;
    				do{
    					L[j+gap]=L[j];
    					j=j-gap;
    				}while(j>=left&&temp<L[j]);
    				L[j+gap]=temp;
    			}
    		 } 
    	}while(gap>1);
    };
    
    

    (三)时间复杂度
    O(n^(1.3—2))

    四、插入排序

    (一)每一个元素与其前面已经有序的元素比较,插入到合适的位置。
    (二)代码
    (1)直接插入排序

    #include"dataList.h"
    template<class T>
    void InsertSort(dataList<T>&L,const int left,const int right)
    {
    	Element<T>temp;int i,j;
    	for(int i=left+1;i<=right;i++) //i是当前准备要插入的元素,1---i-1都是有序的 
    	{                                         //一共需要插入n-1 
    		if(L[i]<L[i-1])                      //需要插入 
    		{
    			temp=L[i];                       //保存当前插入元素,防止丢失 
    			j=i-1;                           
    			do{
    				L[j+1]=L[j];j--;           //后移 
    			}while(j>=left&&temp<L[j]);   //j必须是小于i的第一个元素 如果j大于i就需要一直跳 
    			L[j+1]=temp;
    		}
    	}
    } 
    
    ----------------------------------------
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 1000009
    using namespace std;
    
    int n;
    int a[N];
    
    void InsertSort(int a[],int left,int right)
    {
    	int temp,j; 
    	for(int i=left+1;i<=right;i++)
    	{
    		if(a[i]<a[i-1])
    		{
    			temp=a[i];
    			j=i-1;
    			do{
    				a[j+1]=a[j];j--;
    			}while(j>=left&&a[j]>temp);
    			a[j+1]=temp;
    		}	  
    	}
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    	}
    	InsertSort(a,1,n);
    	for(int i=1;i<=n;i++)
    	{
    		printf("%d ",a[i]);
    	}
    	return 0;
    } 
    
     
    

    (2)折半插入排序

    #include"dataList.h"
    template<class T>
    void BinaryInsertSort(dataList<T>&L,const int left,const int right)
    {
    	Element<T>temp;int i,low,high,middle,k;
    	for(int i=left+1;i<=right;i++)  //i为当前插入元素,一共插入n-1次,left---i-1都为有序的 
    	{
    		temp=L[i];low=left;high=i-1;          //在[left,high]区间内寻找大于a[i]的最小元素 
    		while(low<=high)
    		{
    			middle=(low+high)/2;
    			if(temp<L[middle])
    			 high=middle-1;
    			else low=middle+1;
    		}
    		for(k=i-1;k>=low;k--) L[k+1]=L[k];  //[low,i-1]后移 
    		L[low]=temp;                    //low就是插入的位置 
    	}
    } 
    
    
    
    
    
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define N 100009
    using namespace std;
    
    int n;
    int a[N];
    
    void BinaryInsertSort(int a[],int left,int right)
    {
    	int i,low,high,middle,k,temp;
    	for(int i=left+1;i<=right;i++)
    	{
    		temp=a[i];low=left;high=i-1;
    		while(low<=high)
    		{
    			middle=(low+high)/2;
    			if(a[middle]>temp)
    			{
    				high=middle-1;
    			}else low=middle+1;
    		}
    		for(k=i-1;k>=low;k--) a[k+1]=a[k];
    		a[low]=temp;
    	}
    }
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	BinaryInsertSort(a,1,n);
    	for(int i=1;i<=n;i++)
    	{
    		printf("%d ",a[i]);
    	}
    	return 0;
    } 
    

    (三)时间复杂度
    (1)直接插入 O(n^2)
    (2)折半插入 O(n^2)

    五、归并排序

    (一)原理:递归减少区间大小,然后再合并。
    (二)代码

    //归并排序 
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    int n,a[100009],tmp[100009];
    
    void merge_sort(int l,int r){
        if(l==r)return;
        int mid=(l+r)>>1;
        merge_sort(l,mid);
        merge_sort(mid+1,r);
        int ii=l,jj=mid+1,k=l;
        while(ii<=mid&&jj<=r){
            if(a[ii]<a[jj])tmp[k++]=a[ii++];
            else tmp[k++]=a[jj++];
        }
        while(ii<=mid)tmp[k++]=a[ii++];
        while(jj<=r)tmp[k++]=a[jj++];
        for(int i=l;i<=r;i++)a[i]=tmp[i];
    }
    
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        merge_sort(1,n);
        for(int i=1;i<=n;i++)cout<<a[i]<<" ";
        return 0;
    }
    //----------------------------------- 
    
    
    #include"dataList.h"
    template<class T>
    void merge(dataList<T>&L1,dataList<T>&L2,const int left,const int mid,const int right)
    {
    	for(int k=left;k<=right;k++) L2[k]=L1[k];
     	int s1=left,s2=mid+1,t=left;
     	while(s1<=mid&&s2<=right)//s1和s2是检测指针,t是存放指针 
     	{
     		if(L2[s1]<=L2[s2]) L1[t++]=L2[s1++];
    		 else L1[t++]=L2[s2++]; 
    	}
    	while(s1<=mid) L1[t++]=L2[s1++];
    	while(s2<=right) L1[t++]=L2[s2++];
    }
    
    void mergeSort(dataList<T>&L,dataList<T>&L2,int left,int right)
    {
    	if(left>=right) return;
    	int mid=(left+right)/2;
    	mergeSort(L,L2,left,mid);
    	mergeSort(L,L2,mid+1,right);
    	merge(L,L2,left,mid,right); 
    }
    

    (三)时间复杂度
    O(n log n)

    六、选择排序

    (一)原理: 每次选择没被选择元素中最小的放到已经排序的序列里。
    (二)代码

    
    //选择排序 
    #include"dataList.h"
    template<class T>
    void SelectSort(dataList<T>&L,const int left,const int right)
    {
    	for(int i=left;i<right;i++)
    	{
    		int k=i;
    		for(int j=i+1;j<=right;j++)
    		{
    			if(L[j]<L[k]) k=j;
    		}
    		if(k!=i) swap(L[i],L[k]);
    	}
    } 
    
    ============================================
    
    #include<iostream>
    #include<cstdio>
    #define N 1000009
    using namespace std;
    
    int n,a[N];
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=1;i<n;i++)
    	{
    		int k=i;
    		for(int j=i+1;j<=n;j++)
    		{
    			if(a[j]<a[k]) k=j;
    		}
    		swap(a[i],a[k]);
    	}
    	for(int i=1;i<=n;i++) printf("%d ",a[i]);
    	return 0;
    } 
    

    (三)时间复杂度
    O(n^2)

    七、冒泡排序

    (一)原理:相邻元素不停交换,每次都会有一个最小的被挤到序列的一端。
    (二)代码

    //冒泡排序 
    #include<iostream>
    #include<cstdio>
    #define N 100009
    using namespace std;
    
    int n;
    int a[N];
    
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=1;i<n;i++)
    	{
    		for(int j=1;j<=n-i;j++)
    		{
    			if(a[j]>a[j+1]) swap(a[j],a[j+1]);
    		}
    	}
    	for(int i=1;i<=n;i++) printf("%d ",a[i]);
    	return 0;
    } 
    

    (三)时间复杂度
    O(n^2)

    第一次用markdown....
    整理太费时间了...不考的我下次不整了...

  • 相关阅读:
    自执行函数的几种不同写法的比较
    Textarea与懒惰渲染
    备忘:递归callee.caller导致死循环
    围观STK
    某台机器上IE8抛“Invalid procedure call or argument”异常
    QWrap Selector之W3C版
    onclick与listeners的执行先后问题
    随机问题之洗牌算法
    selector4 之 巧妙的主体定义符
    神奇的"javascript:"
  • 原文地址:https://www.cnblogs.com/zzyh/p/13178986.html
Copyright © 2011-2022 走看看