排序
快速排序:
基本思想:
1.选定一个合适的值(理想情况中值最好,但实现中一般使用数组第一个值),称为“枢轴”(pivot)。
2.基于这个值,将数组分为两部分,较小的分在左边,较大的分在右边。
3.可以肯定,如此一轮下来,这个枢轴的位置一定在最终位置上。
4.对两个子数组分别重复上述过程,直到每个数组只有一个元素。
5.排序完成。
void mysort(int a[], int low, int high) { int i=low; int j=high; if (i < j) { int temp = a[low]; while(i < j) { while(a[j]>=temp && i<j) j--; a[i] = a[j]; while (a[i]<=temp && i<j) i++; a[j] = a[i]; } a[i] = temp; mysort(a, low, i-1); mysort(a, i+1, high); } }
冒泡排序
基本思想是:比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
void mysort(int a[], int n) { for (int i=0; i<n; i++) { for (int j=0; j<n-1-i; j++) { if (a[j] > a[j+1]) std::swap(a[j], a[j+1]); } } }
直接插入排序:
基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子序列中的适当位置,直到全部记录插入完成为止。
void mysort(int a[], int n) { for (int i=1; i<n; i++) { int j; int temp = a[i]; for (j=i-1; j>=0; j--) { if (a[j] < temp) break; } for (int k=i-1; k>j; k--) { a[k+1] = a[k]; } a[j+1] = temp; } }
折半插入排序:
基本思想:
折半插入排序的基本思想与直接插入排序一样,在插入第i(i≥1)i(i≥1)个元素时,前面i−1i−1个元素已经排好序。区别在于寻找插入位置的方法不同,折半插入排序是采用折半查找法来寻找插入位置的。
折半查找法的基本思路是:用待插元素的值与当前查找序列的中间元素的值进行比较,以当前查找序列的中间元素为分界,确定待插元素是在当前查找序列的左边还是右边,如果是在其左边,则以该左边序列为当前查找序列,右边也类似。按照上述方法,递归地处理新序列,直到当前查找序列的长度小于1时查找过程结束。
void mysort(int a[], int n) { int low,high, mid; for (int i=1; i<n; i++) { int temp = a[i]; low = 0; high = i-1; while(low <= high) { mid = (low+high)/2; if (a[mid] < temp) low = mid+1; else high = mid-1; } for (int j=i-1; j>high; j--)//最后一次判断决定是插入在low==higi时这个数之前还是之后 { a[j+1] = a[j]; } a[high+1] = temp; } }
希尔排序:
基本思想:
先比较距离远的元素,而不是像简单交换排序算法那样先比较相邻的元素,这样可以快速减少大量的无序情况,从而减轻后续的工作。被比较的元素之间的距离逐步减少,直到减少为1,这时的排序变成了相邻元素的互换。
void mysort(int a[], int n) { int gap = n; while ((gap /= 2) > 0) { for (int i=gap; i<n; i++) { int temp = a[i]; int j; for (j=i-gap; j>=0; j-=gap) { if (a[j] > a[j+gap]) std::swap(a[j], a[j+gap]); } } } }
堆排序:
基本思想:
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
void make_max_heap(int a[], int begin, int end) { int father = begin; int son = 2*father+1; while(son < end)//子节点有效才进行比较 { if (son+1<end && a[son]<a[son+1])//去两个子节点中较大的字节进行比较 son++; if (a[son] > a[father])//判断子节点是否大于父节点,是则交换 { std::swap(a[son], a[father]); father = son; son = father*2+1; } else//父节点比两个子节点都大不用交换 { return; } } } void mysort(int a[], int n) { for (int i=n/2-1; i>=0; i--)//初始化大顶堆 { make_max_heap(a, i, n); } for (int i=n-1; i>0; i--)//将堆顶元素与堆尾元素交换,除了堆尾元素其余的再次构建大顶堆 { std::swap(a[0], a[i]); make_max_heap(a, 0, i);//除了堆顶其余的都保持大顶堆关系,所以从0开始就行,不用像初始化一样从底向上循环 } }
归并排序:
基本思想:
基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?
可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。
void merge_array(int a[], int first, int mid, int last, int temp[]) { int i=first, j=mid+1; int n=mid, m=last; int k=0; while (i<=n && j<=m) { if (a[i] < a[j]) { temp[k++] = a[i++]; } else { temp[k++] = a[j++]; } } while (i<=n) { temp[k++] = a[i++]; } while (j<=m) { temp[k++] = a[j++]; } for (i=0; i<k; i++) { a[first+i] = temp[i]; } } void merge_sort(int a[], int start, int end, int temp[]) { if (start < end) { int mid = (start + end) / 2; merge_sort(a, start, mid, temp); merge_sort(a, mid+1, end, temp); merge_array(a, start, mid, end, temp); } } void mysort(int a[], int n) { int *p = new int[n]; if (NULL == p) return; merge_sort(a, 0, n-1, p); delete[] p; }