数据结构学习笔记排序 (快速,表排序,基数排序)
2017-05-20 18:01
246 查看
layout: post
title: 数据结构学习笔记排序 (快速,表排序,基数排序)
date: 2017-05-20
tag: 数据结构和算法
---
{:toc}
采用分而治之思想
最好的情况:每次主元正好中分,T(N)=O(NlogN)
最坏情况:每次主元一边倒,T(N)=O(N*N)
选主元 的方法有很多,这里用 取头、中、尾的中位数。
快速排序的之所以快:在于每次对于主元一次就可以放到指定位置
小规模数据的处理:
快速排序的问题:用递归……
对小规模的数据(例如N不到100)可能还不如插入排序快
当递归的数据规模充分小,则停止递归,直接调用简单排序(例如插入排序)在程序中定义一个Cutoff的阈值
快速排序 - 直接调用库函数
用的较多的快速排序
学习地址视频
LSD(Least Significant Digit)次为优先
MSD(Most Significant Digit)主位优先
LSD和MSD适合不同的场合,速度不一样
多关键排序时候,先MSD,在LSD
title: 数据结构学习笔记排序 (快速,表排序,基数排序)
date: 2017-05-20
tag: 数据结构和算法
---
目录
TOC{:toc}
快速排序
不稳排序采用分而治之思想
最好的情况:每次主元正好中分,T(N)=O(NlogN)
最坏情况:每次主元一边倒,T(N)=O(N*N)
选主元 的方法有很多,这里用 取头、中、尾的中位数。
快速排序的之所以快:在于每次对于主元一次就可以放到指定位置
小规模数据的处理:
快速排序的问题:用递归……
对小规模的数据(例如N不到100)可能还不如插入排序快
当递归的数据规模充分小,则停止递归,直接调用简单排序(例如插入排序)在程序中定义一个Cutoff的阈值
Qsort实现
C:qsort();C:sort();当时自定义的数据结构时,需要自定义实现比较函数快速排序 - 直接调用库函数
#include<stdio.h> #define ElementType int void InsertionSort(ElementType A[], int N) { int i; for (int P = 1; P<N; P ++ ) { ElementType temp = A[P];//取出未排序序列中的第一个元素 for (i = P; i >0 && A[i - 1] > temp; i--) { /* code */ A[i] = A[i - 1]; //依次与已排序序列中元素比较并右移 } A[i] = temp; } } //快速排序 ElementType Median3(ElementType A[], int Left, int Right) { int Center = (Left + Right) / 2; int temp; if (A[Left] > A[Center]) { temp = A[Left]; A[Left] = A[Center]; A[Center] = temp; } if (A[Left] > A[Right]) { temp = A[Left]; A[Left] = A[Right]; A[Center] = temp; } if (A[Center] > A[Right]) { temp = A[Center]; A[Center] = A[Right]; A[Right] = temp; } /*此时A[Left]<=A[Center]<=A[Right]*/ temp = A[Center]; A[Center] = A[Right - 1]; A[Right - 1] = temp; //将基准Pivot藏到右边 //只需要考虑A[Left+1]...到A[Right-2]的元素 return A[Right - 1]; } void Qsort(ElementType A[], int Left, int Right) { /*核心递归函数*/ int Pivot, CutOff=1000, Low, High; int temp; if (CutOff <= Right - Left) { //如果序列元素充分多,进入快排 Pivot = Median3(A, Left, Right); //选基准,返回中位数 Low = Left; High = Right - 1; while (1) //将序列中比基准小的移动到基准左边,大的移动到右边 { while (A[++Low]<Pivot); while (A[--High]>Pivot); if (Low < High) { temp = A[Low]; A[Low] = A[High]; A[High] = temp; } else break; } temp = A[Low]; A[Low] = A[Right - 1]; A[Right - 1] = temp; //将基准换到正确的位置,快速排序之所以快,就在于一次性将元素的位置放到正确的位置 Qsort(A, Left, Low - 1); //递归解决左边 Qsort(A, Low + 1, Right); //递归解决右边 } else { InsertionSort( A+Left, Right-Left+1); //元素太少,用简单排序 } } void QuickSort(ElementType A[], int N) { Qsort(A, 0, N - 1); //统一接口,排序子问题的左右下标 } int main(int argc, char const *argv[]) { int a[] = { 34, 8, 64, 51, 32, 21 }; QuickSort(a, 6); for (int i = 0; i < sizeof(a) / sizeof(int); ++i) { /* code */ printf("%d ", a[i]); } return 0; }
用的较多的快速排序
//快速排序 O(N*log(N)) #include <math.h> class QuickSort { public: int* quickSort(int* A, int n) { // write code here quickSort(A, 0, n - 1); return A; } void quickSort(int* A, int low, int high) { if (low <= high) { int part = partition(A, low, high); quickSort(A, low, part - 1); quickSort(A, part + 1, high); } return; } int partition(int* A, int low, int high) { int privotKey = A[low]; //基准元素 while (low < high) { //从表的两端交替地向中间扫描 while (low < high && A[high] >= privotKey) --high; //从high 所指位置向前搜索,至多到low+1 位置。将比基准元素小的交换到低端 swap(&A[low], &A[high]); while (low < high && A[low] <= privotKey) ++low; swap(&A[low], &A[high]); } return low; } };
表排序
表排序适合就是数据本身容量大,交换代价比较大,我们只需要对其下标进行操作学习地址视频
基数排序
桶排序
N>>M时,复杂度:T(N,M)=O(M+N);M>>N桶排序不合理基数排序
M>>N时,T(N)=O(P(N+B)),B->Bucket,P->趟数LSD(Least Significant Digit)次为优先
MSD(Most Significant Digit)主位优先
LSD和MSD适合不同的场合,速度不一样
LSD基数排序实现
#include<stdio.h> #include <stdlib.h> typedef int ElementType; //基数排序,次为优先 //假设元素最多有MaxDigit个关键字,基数全部是同样的Tadix #define MaxDigit 4 #define Radix 10 //桶元素节点 typedef struct Node *PtrToNode; struct Node { int key; PtrToNode next; }; //桶头节点 struct HeadNode { PtrToNode head, tail; }; typedef struct HeadNode Bucket[Radix]; int GetDigit(int X, int D) { //默认次位D=1,主位D<=MaxDigit int d, i; for (i = 1; i <= D;i++) { d = X%Radix; X /= Radix; } return d; } int LSDRadixSort(ElementType A[], int N) { int D, Di, i; Bucket B; PtrToNode temp, p, List = NULL; for (i = 0; i < Radix;i++) /* 初始化每个桶为空链表 */ { B[i].head = B[i].tail = NULL; } for (i = 0; i < N; i++) /* 将原始序列逆序存入初始链表List */ { temp = (PtrToNode)malloc(sizeof(struct Node)); temp->key = A[i]; temp->next = List; List = temp; } for (D = 1; D <= MaxDigit;D++) /* 对数据的每一位循环处理 */ { /* 下面是分配的过程 */ p = List; while (p) { Di = GetDigit(p->key, D); //获取当前元素的当前位数字 //从List中摘除 temp = p; p = p->next; //插入B[Di]号的桶尾 temp->next = NULL; if (B[Di].head==NULL) { B[Di].head = B[Di].tail = temp; } else { B[Di].tail->next = temp; B[Di].tail = temp; } } //下面是收集的过程 List = NULL; for (Di = Radix - 1; Di >= 0;Di--) /* 将每个桶的元素顺序收集入List */ { if (B[Di].head) //如果桶不为空 { //整桶插入List表头中 B[Di].tail->next = List; List = B[Di].head; B[Di].head = B[Di].tail = NULL; //清空桶 } } } //将List倒入A[]并释放空间 for (i = 0; i < N;i++) { temp = List; List = List->next; A[i] = temp->key; free(temp); } return 0; } int main() { int a[] = {34,8,64,51,32,21}; LSDRadixSort(a,6); for (int i = 0; i < 6;i++) { printf("%d ", a[i]); } return 0; }
MSD基数排序实现
#include <stdio.h> #include <stdlib.h> typedef int ElementType; /* 基数排序 - 主位优先 */ /* 假设元素最多有MaxDigit个关键字,基数全是同样的Radix */ #define MaxDigit 4 #define Radix 10 /* 桶元素结点 */ typedef struct Node *PtrToNode; struct Node{ int key; PtrToNode next; }; /* 桶头结点 */ struct HeadNode { PtrToNode head, tail; }; typedef struct HeadNode Bucket[Radix]; int GetDigit ( int X, int D ) { /* 默认次位D=1, 主位D<=MaxDigit */ int d, i; for (i=1; i<=D; i++) { d = X%Radix; X /= Radix; } return d; } void MSD( ElementType A[], int L, int R, int D ) { /* 核心递归函数: 对A[L]...A[R]的第D位数进行排序 */ int Di, i, j; Bucket B; PtrToNode tmp, p, List = NULL; if (D==0) return; /* 递归终止条件 */ for (i=0; i<Radix; i++) /* 初始化每个桶为空链表 */ B[i].head = B[i].tail = NULL; for (i=L; i<=R; i++) { /* 将原始序列逆序存入初始链表List */ tmp = (PtrToNode)malloc(sizeof(struct Node)); tmp->key = A[i]; tmp->next = List; List = tmp; } /* 下面是分配的过程 */ p = List; while (p) { Di = GetDigit(p->key, D); /* 获得当前元素的当前位数字 */ /* 从List中摘除 */ tmp = p; p = p->next; /* 插入B[Di]号桶 */ if (B[Di].head == NULL) B[Di].tail = tmp; tmp->next = B[Di].head; B[Di].head = tmp; } /* 下面是收集的过程 */ i = j = L; /* i, j记录当前要处理的A[]的左右端下标 */ for (Di=0; Di<Radix; Di++) { /* 对于每个桶 */ if (B[Di].head) { /* 将非空的桶整桶倒入A[], 递归排序 */ p = B[Di].head; while (p) { tmp = p; p = p->next; A[j++] = tmp->key; free(tmp); } /* 递归对该桶数据排序, 位数减1 */ MSD(A, i, j-1, D-1); i = j; /* 为下一个桶对应的A[]左端 */ } } } void MSDRadixSort( ElementType A[], int N ) { /* 统一接口 */ MSD(A, 0, N-1, MaxDigit); } int main() { int a[] = {34,8,64,51,32,21}; MSDRadixSort(a, 6); for(int i = 0; i < 6; i++) printf("%d ",a[i]); return 0; }
多关键排序时候,先MSD,在LSD
总结
Reference
排序算法的实现(归并,快排,堆排,希尔排序 O(N*log(N)))相关文章推荐
- 排序方法了解一下(冒泡排序、选择排序、堆排序、插入排序、希尔排序、归并排序、快速排序、基数排序)
- 排序(插入排序、折半插入排序、希尔排序、冒泡排序、快速排序、简单选择排序、堆排、归并排序、基数排序)
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法, 冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
- [C++]数据结构:排序算法Part2----快速排序、归并排序、箱子排序、基数排序
- 常用排序算法C++实现(堆排序,快速排序,归并排序,基数排序)
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序
- 排序总结:堆排序、快速排序、归并排序、基数排序
- 几种排序算法的C++实现——快速排序、堆排序、基数排序
- 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析(好戏在后面,有图有真相)
- 各种排序算法实现——基数排序、归并排序、插入排序、冒泡排序、选择排序、快速排序、堆排序、希尔排序
- java排序之快速排序、归并排序、基数排序
- 选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
- 【Java】快速排序、归并排序、堆排序、基数排序实现总结
- 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析(好戏在后面,有图有真相)
- 排序算法复习(Java实现):插入,冒泡,选择,Shell,快速排序, 归并排序,堆排序,桶式排序,基数排序
- 浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析(好戏在后面,有图有真相)
- 数据结构与算法从零开始系列:冒泡排序、选择排序、插入排序、希尔排序、堆排序、快速排序、归并排序、基数排序
- 几种常见的排序算法,选择排序,冒泡排序,希尔排序,堆排序,快速排序,归并排序,基数排序的比较
- 冒泡排序,熙儿排序,快速排序,插入排序,堆排序,基数排序性能对比