赞
踩
1.插入排序
代码实现:
- //直接插入排序
- void insert_sort(int* a, int k)
- {
- for (int i = 0; i < k - 1; i++)
- {
- int end = i;
- int tmp = a[end + 1];
- while (end >= 0)
- {
- if (a[end] > tmp)
- {
- //将前一个数覆盖后一个数
- a[end + 1] = a[end];
- end--;
- }
- else
- {
- break;
- }
- //将tmp插入到大于或者小于的那个数的后面
- a[end + 1] = tmp;
- }
- }
- }
2.希尔排序
希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。
从下图可以看出:
gap越大时,大的数更快的跳到后面,但是数据更不接近有序。
gap越小时,大的数跳到后面更慢,但是数据更接近有序。
排序原理如下:
代码实现:
- void shell_sort(int* a, int k)
- {
- int gap = k;
- while (gap > 1)
- {
- gap = gap / 3 + 1;
- //确定排序次数
- for (int i = 0; i < gap; i++)
- {
- for (int j = i; j < k - gap; j+=gap)
- {
- int end = j;
- int tmp = a[end + gap];
- while (end >= 0)
- {
- if (a[end] > tmp)
- {
- a[end + gap] = a[end];
- end -= gap;
- }
- else
- {
- break;
- }
- }
- a[end + gap] = tmp;
- }
- }
- }
- //优化方案
- int gap = k;
- while (gap > 1)
- {
- gap = gap / 3 + 1;
- for (int i = 0; i < k - gap; i++)
- {
- int end = i;
- int tmp = a[end + gap];
- while (end >= 0)
- {
- if (tmp < a[end])
- {
- a[end + gap] = a[end];
- end -= gap;
- }
- else
- {
- break;
- }
- }
- a[end + gap] = tmp;
- }
- }
- }
希尔排序特性归纳总结:
将上述选择排序进行优化,依次选出最大值和最小值依次和第一个位置和最后一个位置交换,具体思想如下图:
代码如下:
- void select_sort(int* a, int k)
- {
- int begin = 0, end = k - 1;
- while (begin < end)
- {
- //假设最小值下标和最大值下标为begin位置
- int mini = begin, maxi = begin;
- for (int i = begin+1; i <= end; i++)
- {
- if (a[i] < a[mini])
- mini = i;
- if (a[i] > a[maxi])
- maxi = i;
- }
- swap(a[mini], a[begin]);
- //最大值下标在begin位置,但是begin位置的值被最小换走了
- //所以最大值就在mini下标的位置
- if (a[maxi]==a[begin])
- maxi = mini;
- swap(a[maxi], a[end]);
- begin++;
- end--;
- }
- }
4.堆排序
- void adjust_down(int* a, int parent,int n)
- {
- int child = parent * 2 + 1;
- while (child < n)
- {
- //找最大孩子或者最小孩子
- if (child + 1 < n && a[child + 1] > a[child])
- child++;
- if (a[child] > a[parent])
- {
- swap(a[child], a[parent]);
- parent = child;
- child = parent * 2 + 1;
- }
- else
- {
- break;
- }
- }
- }
-
- //堆排序
- void heap_sort(int* a, int k)
- {
- //向下调整法建堆 时间复杂度O(n)
- for (int i =(k-1-1)/2; i >=0; i--)
- {
- adjust_down(a, i, k);
- }
- //排序
- for (int i = k - 1; i >= 1; i--)
- {
- swap(a[0], a[i]);
- adjust_down(a, 0, i);
- }
- }
堆排序的特性总结:
5.冒泡排序
代码如下:
- //冒泡排序
- void bubble_sort(int* a, int k)
- {
- for (int i = 0; i < k - 1; i++)
- {
- //如果下面没有交换证明已经有序,则中断循环
- int exchange = 0;
- for (int j = 1; j < k - i; j++)
- {
- if (a[j - 1] > a[j])
- {
- swap(a[j - 1], a[j]);
- exchange = 1;
- }
- }
- if (exchange == 0)
- {
- break;
- }
- }
- }
- // 假设按照升序对array数组中[left, right)区间中的元素进行排序
- void QuickSort(int array[], int left, int right)
- {
- if(right - left <= 1)
- return;
-
- // 按照基准值对array数组的 [left, right)区间中的元素进行划分
- int div = partion(array, left, right);
-
- // 划分成功后以div为边界形成了左右两部分 [left, div) 和 [div+1, right)
- // 递归排[left, div)
- QuickSort(array, left, div);
-
- // 递归排[div+1, right)
- QuickSort(array, div+1, right);
- }
- //hoare单趟排序
- int part_sort1(int* a, int left, int right)
- {
- int keyi = left;
- while (left < right)
- {
- while (left < right && a[right] >= a[keyi])
- {
- right--;
- }
- while (left < right && a[left] <= a[keyi])
- {
- left++;
- }
- swap(a[left], a[right]);
- }
- swap(a[keyi], a[left]);
- //找到单趟排序的key位置
- return left;
- }
b. 挖坑法版本
代码如下:
- //挖坑法,更易理解
- int part_sort2(int* a, int left, int right)
- {
- int pit = left;
- int key = a[left];
- while (left<right)
- {
- //找小,找到小于key就停下来,填坑
- while (left < right && a[right] >= key)
- //注意:a. 每次结束必须判断left和right关系,防止越界非法访问
- //b. 必须>=否则就会死循环,栗子:(5,5,5)
- {
- right--;
- }
- a[pit] = a[right];
- pit = right;
- //找大,找到大于key就停下来,填坑
- while (left < right && a[left] <= key)
- {
- left++;
- }
- a[pit] = a[left];
- pit = left;
- }
- //把第一个数key填到pit位置
- a[pit] = key;
- return pit;
- }
c. 双指针法
思想如下:
代码如下:
- //双指针法
- int part_sort3(int* a, int left, int right)
- {
- int prev = left;
- int cur = left+1;
- int key = a[left];
- while (cur <=right)
- {//找大,遇到小的就停下来交换,遇到大的就往前走
- if (a[cur] < key && (++prev) != cur)
- {
- swap(a[cur], a[prev]);
- }
- cur++;
- }
- swap(a[prev], a[left]);
- return prev;
- }
完整的快速排序实现:分治,排完keyi位置,keyi位置保持不变,再使用递归思想排keyi左右两边,[begin,keyi-1] keyi [keyi+1,end],左边有序右边有序,排序就完成有序。
整趟代码如下:
- //快速排序
- void quick_sort(int* a, int begin, int end)
- {
- if (begin >= end)
- {
- return;
- }
- //三数取中,保证二分,降低递归层数
- int mid = get_mid_index(a, begin, end);
- swap(a[mid], a[begin]);
- //小区间优化,防止数据太大,递归层次太深,栈溢出
- if ((end - begin) >= 10)
- {
- insert_sort(a+begin,end-begin+1);
- }
- else
- {
- //单躺排序
- int keyi = part_sort3(a, begin, end);
- //左边有序
- quick_sort(a, begin, keyi - 1);
- //右边有序
- quick_sort(a, keyi + 1, end);
- }
- }
优化快速排序:a.三数取中 b.小区间优化
三数取中代码如下:
- int get_mid_index(int* a,int begin, int end)
- {
- int mid = (begin + end) / 2;
- if (a[begin] < a[end])
- {
- if (a[begin] > a[mid])
- return begin;
- else if (a[mid] > a[end])
- return end;
- else
- return mid;
- }
- //a[begin]>a[end]
- else
- {
- if (a[end] > a[mid])
- return end;
- else if (a[begin] > a[mid])
- return mid;
- else
- return begin;
- }
- }
6.2 非递归实现
思想如下:
代码如下:
- //用一个栈模拟快速排序非递归实现
- void quick_sort_nonR(int* a, int begin, int end)
- {
- stack<int> s;
- s.push(end);
- s.push(begin);
- while (!s.empty())
- {
- int begin = s.top();
- s.pop();
- int end = s.top();
- s.pop();
- int keyi = part_sort1(a, begin, end);
- if (keyi + 1 < end)
- {
- s.push(end);
- s.push(keyi + 1);
- }
- if (begin < keyi - 1)
- {
- s.push(keyi - 1);
- s.push(begin);
- }
- }
- }
基本思想:
- //子区间
- void _merge_sort(int* a, int begin, int end, int* tmp)
- {
- //先递归分解,后序
- if (begin = end)
- {
- return;
- }
- int mid = (end + begin) / 2;
- _merge_sort(a, begin, mid, tmp);
- _merge_sort(a, mid + 1, end, tmp);
- //归并排序
- int begin1 = begin, end1 = mid;
- int begin2 = mid + 1,end2 = end;
- int i = begin1;
- //取俩组区间内小的值依次放在a数组和tmp数组下标对应的位置中
- //当一个区间内没有数了,则把另外一个区间内的数依次放入tmp数组中
- while (begin1 <= end1 && begin2 <= end2)
- {
- if (a[begin1] < a[begin2])
- {
- tmp[i++] = a[begin1++];
- }
- else
- {
- tmp[i++] = a[begin2++];
- }
- }
- while (begin1 <= end1)
- {
- tmp[i++]= a[begin1++];
- }
- while (begin2 <= end2)
- {
- tmp[i++] = a[begin2++];
- }
- //拷贝tmp数组内数据回原数组a中
- memcpy(a + begin, tmp + begin, sizeof(int)*(end-begin+1));
- }
-
- /归并排序
- oid merge_sort(int* a, int begin, int end)
- {
- int* tmp = new int[end - begin + 1];
- _merge_sort(a, begin, end,tmp);
- }
7.2非递归实现
思想如下:
但是上述思想只适合于数据个数是2^n,不是2^n的数据会有一定的越界,根据下面代码打印可得:
- void merge_sort_nonR(int* a, int begin, int end)
- {
- int* tmp = new int[end - begin + 1];
- int gap = 1;
- int n = end - begin + 1;
- while (gap < n)
- {
- cout << "gap->" << gap << " ";
- for (int i = 0; i < n; i +=2*gap)
- {
- int begin1 = i, end1 = gap+i-1;
- int begin2 = gap + i, end2 = i+2*gap-1;
- printf("[%d,%d]-[%d,%d] ", begin1, end1, begin2, end2);
- int j = begin1;
- while (begin1 <= end1 && begin2 <= end2)
- {
- if (a[begin1] < a[begin2])
- {
- tmp[j++] = a[begin1++];
- }
- else
- {
- tmp[j++] = a[begin2++];
- }
- }
- while (begin1 <= end1)
- {
- tmp[j++] = a[begin1++];
- }
- while (begin2 <= end2)
- {
- tmp[j++] = a[begin2++];
- }
- }
- printf("\n");
- memcpy(a, tmp, sizeof(int) * (n));
- gap *= 2;
- }
- }
结果如图所示:
正确代码:
- void merge_sort_nonR(int* a, int begin, int end)
- {
- int n = end - begin + 1;
- int* tmp = new int[n];
- int gap = 1;
- while (gap < n)
- {
- cout << "gap->" << gap << " ";
- for (int i = 0; i < n; i +=2*gap)
- {
- int begin1 = i, end1 = gap+i-1;
- int begin2 = gap + i, end2 = i+2*gap-1;
- if (end1 >= n)
- {
- //将end1修回最后一个数的下标位置
- end1 = n - 1;
- //begin2和end2修成不存在的区间
- begin2 = n;
- end2 = n - 1;
- }
- if (begin2 >= n)
- {
- begin2 = n;
- end2 = n - 1;
- }
- if (end2 >= n)
- {
- end2 = n - 1;
- }
- printf("[%d,%d]-[%d,%d] ", begin1, end1, begin2, end2);
- int j = begin1;
- while (begin1 <= end1 && begin2 <= end2)
- {
- if (a[begin1] < a[begin2])
- {
- tmp[j++] = a[begin1++];
- }
- else
- {
- tmp[j++] = a[begin2++];
- }
- }
- while (begin1 <= end1)
- {
- tmp[j++] = a[begin1++];
- }
- while (begin2 <= end2)
- {
- tmp[j++] = a[begin2++];
- }
- //拷贝tmp数组内数据回原数组a中
- }
- printf("\n");
- memcpy(a, tmp, sizeof(int) * (n));
- gap *= 2;
- }
- }
归并排序的特性总结:
8.计数排序
思想:
1. 统计相同元素出现次数 2. 根据统计的结果将序列回收到原来的序列中
看图更清晰:
具体实现请看代码:
- //计数排序
- void count_sort(int* a, int k)
- {
- //遍历求数组中的最大和最小值
- int max = a[0], min = a[0];
- for (int i = 1; i < k; i++)
- {
- if (a[i] < min)
- min = a[i];
- if (a[i] > max)
- max = a[i];
- }
- //求新开辟计数的数组空间大小
- int rage = max - min + 1;
- int* tmp = new int[rage];
- //初始化tmp中的数据为0
- memset(tmp, 0, sizeof(int) * rage);
- //在tmp数组中计a数组中数据出现的个数
- for (int i = 0; i < k; i++)
- {
- //相对映射
- tmp[a[i] - min]++;
- }
- //排序,拷贝数据回原数组中
- int i = 0;
- for (int j = 0; j < rage; j++)
- {
- while (tmp[j]--)
- {
- //回写
- a[i++] = j + min;
- }
- }
- delete[] tmp;
- }
计数排序特性总结:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。