1、插入排序
插入排序的工作原理是建立有序序列,对于未排序数据,在已排序的数据从后先前扫描,找到对应的位置后插入。
①从第一个元素开始,该元素被默认为有序序列。
②从下一个未排序数据开始,在已经排序的序列中从后往前扫描
③如果该元素小于已排序的元素,继续往前扫描
④重复③,直到找到该元素大于或等于已排序的元素的位置
⑤插入该元素
⑥重复②
代码:
void InsertSort(int *a,int size) { assert(a); for (int i = 1; i < size; i++) { int index = i; int end = index - 1; //已排序序列最后一个元素下标 int temp = a[index]; //保存未排序数据的值 while (end >= 0 && temp < a[end]) { a[end + 1] = a[end]; //当为排序数据小于已排序序列数据时,把已排序数据向后移一位 end--; //继续往前扫描 } a[end + 1] = temp; //找到未排序数据大于或等于已排序序列,或者整个已排序序列没有一个数小于未排序数据时 } }
插入排序对几乎已经排好序的数据进行操作时,效率很高。但插入排序一般来说是低效的,每次只能挪动数据一位。
2、希尔排序
希尔排序是更优化的插入排序。
其思想为:
把记录按步长 gap 分组,对每组记录采用直接插入排序方法进行排序。随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,整个数据合成为一组,构成一组有序记录,则完成排序。
void ShellSort(int *a, int size) { assert(a); int gap = size; while (gap > 1) { gap = gap / 3 + 1; for (int i = gap; i < size; i++)//比如当gap=4时,并不是让它分别进行4组插入排序,而是采用一种比较巧的方法,让i从gap开始每次加1,这样就能把4组插入排序,一次走完 { int index = i; int temp = a[index]; int end = index - gap; while (end >= 0 && temp<a[end]) { a[end + gap] = a[end]; end -= gap; } a[end + gap] = temp; } } }
3、堆排序
堆排序的思想就是如果是升序排序,则建最大堆,反之,则建最小堆。
建堆过程就是从最后一个非叶子节点直到跟节点向下对齐。假设我们现在要升序排序。即就是向下对齐时,把小的交换到父节点。
void AdjustDown(int *a,int size,int parent) //向下对齐 { int child = parent * 2 + 1; //把左孩子的下标给child while (child < size) //保证向下对齐直到child超出范围 { if (child + 1 < size&&a[child + 1] > a[child]) //当右孩子>左孩子时,child变为右孩子下标 { child++; } if (a[parent] < a[child]) { swap(a[parent],a[child]); parent = child; child = parent * 2 + 1; } else { break; } } } void HeapSort(int *a, int size) { assert(a); for (int i = (size - 2) / 2; i >= 0; i--) { AdjustDown(a,size,i); //从图中下标为4的非叶子节点开始,进行向下对齐 } for (int i = size - 1; i > 0; i--) { swap(a[0],a[i]); //把最大堆中的第一个元素和最后一个元素交换,此时最后一个元素最大 AdjustDown(a,i,0);//把剩余的元素建成最大堆 } }
时间: 2024-11-03 01:38:04