数据结构1:排序

关键字相同的项排序后顺序不变就是稳定的排序算法,否则是不稳定的排序算法。

排序分为内部排序和外部排序,内部排序只需要访问内存,外部排序还需要访问外存。

1.冒泡排序(稳定排序算法)

很经典简单的方法,每个数字从最下面开始一层一层往上走,像冒泡泡一样。

冒泡是用两个嵌套的for循环实现的,基本操作(比较两个数的大小)的执行次数最差是n(n-1)/2,最好的情况下的是有序的,则执行次数是n。

因此,冒泡排序算法的时间复杂度:最差,平均:O(n2),最好:O(n)

空间复杂度:1(原地工作)   只需要交换值,不需要额外的空间

 时间复杂度是一个量级的概念,有点类似于高数里的极限的概念,因此n(n-1)/2可以看成n平方的复杂度。

2.快速排序(不稳定排序算法)

2.1方法:快排是建立在递归的基础上的排序算法,基本思想就是将一个序列分为两部分,再分别给两部分内部排序。

2.2 特点:快排算法的特点是不用交换,直接取代,而且二分法的递归策略很大提高了快排的效率。

2.3 时间复杂度(这个我不会推导)     最好、平均:O(n log(n))       最差:O(n2)

 2.4 空间复杂度:O(log(n))

3.堆排序

3.1 方法 堆排序分为两步,第一步是将一个序列构建成堆,第二步是依次从堆顶去除最大(小)元素,然后重新将剩下的元素构建成堆

3.2 特点 堆排序最大的特点就是时间复杂度稳定,对于数据量大的工作很适合。

3.3 时间复杂度:最差、平均、最好都是O(n log(n))   

3.4 空间复杂度:1(原地工作)

快排是对冒泡的改进,是将冒泡用了分治递归的策略讲一个大问题分解成若干个不相干的子问题。而堆排序是动态规划,将一个问题分解成很多个互相相关的子问题。因此堆排序更加稳定。

4.归并排序

4.1 方法 归并排序是很典型的利用递归分治策略做排序的算法,他把一个序列分为两部分,先给两部分排序然后合并。再把两部分的小序列分开分别排序在合并。这样递归操作一直到只需要排序两个数。

4.2 特点 归并排序是一个稳定的排序算法,但是比较复杂

4.3 时间复杂度:最差、平均、最好都是O(n log(n))   

3.4 空间复杂度:O(n)

 

  1 #include <iostream>
  2 #include<vector>
  3 using namespace std;
  4 //交换两个数
  5 void swaptwo(int& var1,int& var2)
  6 {
  7     int temp=var1;
  8     var1=var2;
  9     var2=temp;
 10 }
 11 //升序冒泡---by myself
 12 /*
 13 void bubblesort(vector<int>& vec)
 14 {
 15     int length=vec.size()-1;
 16     for(int i=0;i<=length;i++)
 17     {
 18         for(int j=i+1;j<=length;j++)
 19         {
 20             if(vec[i]>vec[j])
 21             {
 22                 swaptwo(vec[i],vec[j]);
 23             }
 24         }
 25     }
 26 }*/
 27 //升序冒泡---standard
 28 void bubblesort(vector<int>& vec)
 29 {
 30     int length=vec.size();
 31     for(int i=0;i<length-1;i++)//选定i作为要冒泡的数字,n个数只需要对n-1个数进行冒泡
 32     {
 33         for(int j=0;j<length-i-1;j++)//冒泡的过程,每一个i要经过length-i-1个数字路径的冒泡
 34         {
 35             if(vec[j]>vec[j+1])
 36             swap(vec[j],vec[j+1]);
 37         }
 38     }
 39 }
 40 int partition(vector<int> &vec,int low,int high)//输出序列的第一个数字的正确排序的坐标
 41 {
 42     int pivotkey=vec[low];//寻找第一个值的正确位置
 43     while(low<high)
 44     {
 45         while(low<high&&vec[high]>=pivotkey) --high;
 46         vec[low]=vec[high];
 47         while(low<high&&vec[low]<=pivotkey)  ++low;
 48         vec[high]=vec[low];
 49     }
 50     vec[low]=pivotkey;
 51     return low;
 52 }
 53 void Qsort(vector<int> &vec,int low,int high)//给序列分为两部分并递归每一部分排序
 54 {
 55     if(low<high)
 56     {
 57         int pivotlocation=partition(vec,low,high);
 58         Qsort(vec,low,pivotlocation-1);
 59         Qsort(vec,pivotlocation+1,high);
 60     }
 61 }
 62 void quicksort(vector<int> &vec)
 63 {
 64     int length=vec.size();
 65     //数据检查没写,输入空数据
 66      Qsort(vec,0,length-1);
 67 }
 68 void HeapAdjust(vector<int> &vec,int low,int high)//堆排序的向下筛选,构建一个大顶堆
 69 {
 70     int temp=vec[low];
 71     for(int i=low*2;i<=high;i*=2)
 72     {
 73         if(i<high&&vec[i]<vec[i+1]) ++i;
 74         if(temp>vec[i]) break;//注意这里,为什么这里要用temp作比较呢?因为其实下面两句中low位置和较大的数位置是交换的关系
 75                             //虽然表面是覆盖可是最后是要交换的,只是暂时不知道i位置要放哪个数而已
 76                             //所以交换之后temp这个数值一直都在,在交换之后仍然要判断子树是否为堆
 77         vec[low]=vec[i];
 78         low=i;
 79     }
 80     vec[low]=temp;
 81 }
 82 void heapsort(vector<int> &vec)
 83 {
 84     int length=vec.size()-1;//之前已经给vec里push一个数字了,所以要减掉这个数字
 85     //数据检查
 86     for(int i=length/2;i>=1;--i)//将一个序列构建成一个堆
 87         HeapAdjust(vec,i,length);
 88     for(int i=length;i>1;--i)
 89     {
 90         swap(vec[1],vec[i]);
 91         HeapAdjust(vec,1,i-1);
 92     }
 93 }
 94 void merge(vector<int> &vec,vector<int> sorted,int start,int mid,int end)//将vec以mid为分界点的两个序列合并成一个有序序列
 95 {
 96     int i=start,j=mid+1,k=i;
 97     for(;i<=mid&&j<=end;k++)
 98     {
 99         if(vec[i]<vec[j])
100             sorted[k]=vec[i++];
101         else
102         {
103             sorted[k]=vec[j++];
104         }
105         
106     }
107     while(i<=mid)//最后面的大数字再插到后面
108     {
109         sorted[k++]=vec[i++];
110     }
111     while(j<=end)
112     {
113         sorted[k++]=vec[j++];
114     }
115     k=start;
116     while(start<=end)//将sort中排序好的结果再传给vec,即可将vec排序
117         vec[start++]=sorted[k++];
118 }
119 void Msort(vector<int> &vec,vector<int> sorted,int start,int end)//分开成小序列,再合并
120 {
121     if(start<end)
122     {
123         int mid=(start+end)/2;
124         Msort(vec,sorted,start,mid);//将前半部分变成有序
125         Msort(vec,sorted,mid+1,end);//将后半部分变成有序
126         merge(vec,sorted,start,mid,end);//将这两部分合并
127     }
128 }
129 void mergesort(vector<int> &vec)
130 {
131     int length=vec.size()-1;
132     vector<int> aux(length+1);//这个vector用来存放排序后的结果,由此可见归并排序需要一块额外的同样大小的内存放结果
133     Msort(vec,aux,0,length);
134 }
135 int main() {
136     int inputdata;
137     vector<int> vec;
138     
139     //vec.push_back(-1);//在堆排序里,下标是从1开始的,所以先随便push一个数把下标为0的位占用了。
140     vec={49,38,65,97,76,13,27,49};
141     /*
142      do//单行数据输入
143     {
144         cin >> inputdata;
145         vec.push_back(inputdata);
146     }while(cin.get() != '\n');
147     */
148     //bubblesort(vec);
149     //quicksort(vec);
150     //heapsort(vec);
151     mergesort(vec);
152     for(auto &w:vec)
153     {
154         cout<<w<<" ";
155     }
156     return 0;
157 }

 

posted @ 2019-08-09 16:12  妮妮熊  阅读(163)  评论(0编辑  收藏  举报