直观的视频http://www.cnblogs.com/wangfupeng1988/archive/2011/12/26/2302216.html
1,冒泡排序
——冒泡,每一次最大的值升到最后面,像水泡升到了水面,冒出来了,不再位于水里,不再需要比较,它已经确定了,独立了。
每次从最前面开始比较相邻的两个数,如果前面的大于后面的则交换,直到末尾最后两个,结束后末尾为最大的数。
除去已经找到的最大数,继续从最前开始,两相邻数比较,直到此次数值序列的末尾。
重复以上过程,直到最后一次只有两个数值需要比较。
//the first circle , from 0,1 to ,count-2,cout-1 //the last circle, at 0,1
对每一次的数值序列,记录其是否发生了交换,如果没有,则不需要再进行下一次的循环。
void exchange(uchar * a, uchar *b) { uchar temp; temp = *a; *a = *b; *b = temp; }
//bubble sorting int bubbleSort(int *a, int n) { int i,j; int sentinel; //to signal if exchange happen last run for(j = n - 1; j >= 1 && sentinel; j--) { sentinel = 0; for(i = 0; i<= j - 1; i++) { if(a[i] > a[i + 1]) { swap(&a[i], &a[i + 1]); sentinel = 1; } } } }
2,插入排序
--和冒泡排序逻辑伤相反,冒泡是一次找一个最大值,是个体优先,插入呢,是保证我的序列始终是整齐的,每次放入一个数值到我的序列中。
第一次整齐的序列只有1个数,把相邻的下一个数与这个数相比较,放入合适的位置
下一次,对于排好的序列,再加入下一个数,从序列末尾开始向前依次进行比较,遇到比它大得则交换,遇到比它小的,停止这一次的比较。
重复以上过程,直到最后一次插入最后一个数。
//想到初中时的推理证明题,证明无穷大的情况,从1开始证明, 然后证明n时成立,推导出无穷大时成立。
void insertSort(int *a, int n) { //1st:a[1] into a[0] //2ed:a[n - 1] into a[0]....a[n-2] int i, j; int key; for(j = 1; j <= n - 1; j++) { key = a[j]; for(i = j; i >= 1; i--) { if(a[i - 1] > key) { a[i] = a[i - 1]; } else break; } a[i] = key; } }
3,快速排序
从队列中取一个基数,例如第一个数,其余数依次和这个数比较,比它大的放右边,小的放左边。这一次循环确定了这个基数的排列位置。
对于基数左边和右边的子数列,各自取基数,同第一次循环一样把各个数放基数的两边。
重复以上操作,直到最后一次子序列只有两个数。
----快速排序的优化 http://i.youku.com/u/UMzU2MjI1NzQ0
--小型数组数据的优化。eg,待整理数组个数小于7时,直接用插入排序。
--对于基准值的选取进行优化。讲队列头,尾,中,三个数排序,取中位置的值作为基准
--将递归优化为尾递归。见归并排序。
void quickSort(uchar a[], uchar low, uchar high) { uchar i, j; uchar key; if(low >= high) return; key = a[low]; i = low; j = high; while(j>i) { while(j>i) //end at j = i; { if(a[j] < key) { a[i] = a[j]; //j is hold for key break; } j--; //positon to compare } while(i<j) //i+1 is the one to compare { i++; //positon to compare if(a[i] > key) { a[j] = a[i]; //i is now hold for key break; } } if(j > 0 ) //0-1 should be avoided j--; //positon to comparte } a[i] = key; if(i-1 >= 0) //0-1 should be avoided quickSort(a, low, i-1); quickSort(a, i+1, high); }
void quickSort3(uchar a[], uchar low, uchar high) { uchar i, j; uchar key; if(low >= high) return; key = a[low]; i = low; j = high; while(j>i) { while(j>i && a[j] >= key) { j--; //positon to compare } if(i!=j) { a[i]= a[j];//j is hold for key i++; //this step together with if condition can be omitted } while(i<j && a[i] <= key) { i++; //positon to compare } if(i!=j ) { a[j] = a[i];//i is now hold for key j--; //this step together with if condition can be omitted } } a[i] = key; if(i-1 >= 0) //0-1 should be avoided quickSort3(a, low, i-1); quickSort3(a, i+1, high); }
第二个逻辑清楚,不容易出错。
void quickSortInteration(int *a, int low, int high) { int i,j; int key; if(low >= high) return;
key = a[low]; //set a[low] as key. a[low] is empty now. i = low; //a[i] is empty, wait for date placing j = high; while(i < j) { while( key < a[j] && i < j ) { j--; } a[i] = a[j]; //a[j] is empty,waiting for date placing while( key >= a[i] && i < j ) { i++; } a[j] = a[i]; } a[i] = key; if(i > 1) { quickSortInteration(a, low, i - 1); } quickSortInteration(a, i + 1, high); } //quickSort: sort a[0]..a[n-1] into increasing order void quickSortMy(int *a, int n) { quickSortInteration(a, 0, n -1); }
//其实怎样想都可以,只要能实现就行,唯一可以用思维的地方,总要给个出路。
4,选择排序
选择排序和冒泡排序,一个从没排好的数列里找最大的,一个从没排好的数列里找最小的。选择排序就是选择最小的,一个个排。还不如叫沉泡排序呢。.下面的程序是官方的程序,虽然我本能倾向于程序该和冒泡程序类似的那种,自我开解下要是都一样就没意思了,所以选择官方这种有自己特色的选择排序。
void selectSort(int *a, int n) { //1st get a[0] from a[0]...a[n-1] //last get a[n-2] from a[n-2], a[n-1] int i,j; int min; for(i = 0; i <= n - 2; i++) { min = i; for(j = i + 1;j <= n - 1;j++) { if(a[min] > a[j]) { min = j; } } if(min != i) { swap(&a[min],&a[i]); } } }
5,归并排序
普通话不标准总觉得别扭,不过讲得还行 http://v.youku.com/v_show/id_XNjg1NTQzNTg4.html
---迭代是要用利用已经算出来的一个值去计算下一个值,从远到近,一步步接近答案。递归是要解决的规模逐渐变小。
---递归就是自己调用自己,其运作包括两个过程,先拆后合。递归需要要结束条件。
先递推:将复杂问题简单化。eg,一个数列拆成左右两个部分,各部分再拆成左右两个部分,一直拆下去,直到各部分只剩下一个值为止。再归并:在获得最简单的情况后,逐次返回,得到复杂的解。
---递归的缺点,每进行一次,就要占用一块堆栈空间,容易造成堆栈的溢出。
---尾递归。函数中递归形式的调用出现在末尾。编译器会覆盖当前用的栈空间,而不占用新的占空间。所以只要有可能,使用递归时写成尾递归的形式。
//merge: merge two sorted array void merge(int *a, int *b, int size_a, int size_b) { int i,j,k; int size_buf = size_a + size_b; int *buf = (int *)malloc(sizeof(int) * size_buf); if(buf == NULL) { printf("space alloacted fail"); return; } i = 0; j = 0; k = 0; while(i <= size_a - 1 && j <= size_b) { while(i <= size_a - 1 && a[i] <= b[j]) //store from a[i] { buf[k++] = a[i++]; } while(j <= size_b - 1 && b[j] <= a[i]) //store from b[i] { buf[k++] = b[j++]; } while(i >= size_a && j <= size_b - 1) //a passed, store b { buf[k++] = b[j++]; } while(j >= size_b && i <= size_a - 1) //b passed, store a { buf[k++] = a[i++]; } } for(i = 0; i <= size_buf - 1; i++ ) { a[i] = buf[i]; } free(buf); }
6,希尔排序
插入排序一般而言是低效的,因为一次只能将数据移动一位(//所以快速排序移动的位数最多效率最高吗),对于已经排好的序列,插入排序的效率较高。基于插入排序的特性,产生了更为高效的希尔排序。
就是再进行插入排序之前,对序列先进行一番调整,相隔远得先调一下。取一数值作为步长,将数据分成几个区间,对应值两两相比,再将步长缩小得到更小的区间,从前到后各区间对应位置的值相互比较。最后一次每个区间只剩一个数,就和插入排序一样了。迭代的过程。
void shellSort(uchar a[], uchar n) { uchar step ; uchar i,j,k; for(step=n/2;step>0;step/=2) //step is half decreased here. { for(k = 0;k <= step-1;k++) //move to the next pos { for(j = k+step;j <= n-1;j += step) //compare the values at the same pos { for(i = j;i >= step;i -= step) // i >= k + step is also ok,but confusing { if(a[i-step] > a[i]) exchange(&a[i],&a[i-step]); else break; } } } } }
7, 堆排序
//堆是挺漂亮的结构。
—— 完全二叉树两个条件,n层二叉树
1,from 1 layer to n-1 layer,with max number
2, at n layer, from left to right continuously
——二叉树成为大顶堆的两个条件:1, ki>=k2i 2,ki>=k(2i+1). 1<= i<=n/2.
——堆排序,
1,将大顶堆根节点和末尾节点交换,
2,除去当前末尾最大的数,剩下的数再调整为大顶堆,
3,重复1,2
//adding left>right for handling,not necessary.
void handleChild(uchar a[], uchar n,uchar childIndex) { uchar k; for(k = childIndex;k<=n/2 ;k*=2) { if(a[k] < a[2*k]) swap(&a[k],&a[2*k]); } } void heapSort(uchar a[], uchar n) { uchar i,j; uchar childIndex; uchar heap[i+1];for(i=0;i<=n-1;i++) { heap[i+1] = a[i]; } //repeat the progress for(j=n;j>=2;j--) { //build a big heap.2 conditions:1st,ki>=k2i,2ed,ki>=k2i+1 for(i=j/2;i>=1;i--) { childIndex = 2*i; //adjust to get right > left if(childIndex+1 <= j && heap[childIndex] < heap[childIndex+1]) { swap(&heap[childIndex],&heap[childIndex+1]); handleChild(heap,j,childIndex+1); } //compare father with right if(heap[i] < heap[childIndex]) { swap(&heap[i],&heap[childIndex]); handleChild(heap,j,childIndex); } } //place the root at the end swap(&heap[1],&heap[j]); } printf("%d ..",count); //get the result for(i=1;i<=n;i++) { a[i-1] = heap[i]; } }
uchar count=0; void adjustNode(uchar heap[], uchar i,uchar n) { uchar j; uchar temp = heap[i]; //store node date. for(j=2*i;j<=n;j*=2) //j is left child { count++; if(j+1<=n && heap[j]<heap[j+1]) { j++; //j move to right child } if(temp>heap[j]) { break; } heap[i]=heap[j]; i = j; //current node. } heap[i] = temp; } void heapSort(uchar a[],uchar n) { uchar i; uchar heap[n+1]; //define a heap //build a tree heap[0]=0XFF; for(i=0;i<=n-1;i++) { heap[i+1]=a[i]; } //adjust node to build a heap for(i=n/2;i>=1;i--) { adjustNode(heap,i,n); } //exchange the root node with the last node.adjust the rest date to heap, for(i=n;i>=2;i--) { swap(&heap[1],&heap[i]); //the largest is placed at end. adjustNode(heap,1,i-1); } //return the dates for(i=0;i<=n-1;i++) { a[i]=heap[i+1]; } }
______test function
//scaffolding test:1,sorted;2,values consistent //sorted int sorted(int *a, int n) { int i; for(i = 0; i <= n - 2; i++) { if(a[i] > a[i + 1]) { return 0; } } return 1; } //conform: if conform, return 1;else return 0 int conform(int *a, int *b, int n) { int buf[n]; int i,j; i = n; while(i--) { buf[i] = 0; } for(j = 0; j <= n - 1;j++) { for(i = 0; i <= n - 1;i++) { if(b[j] == a[i] && buf[i] == 0) { buf[i] = 1; break; } } if(i >= n) return 0; } for(i = 0; i <= n -1; i++) { if(0 == buf[i]) return 0; } return 1; }
//memcpy,for scaffolding test. the original array need to be stored void memcpyMy( void *destination, const void *source, int n) { char *dest = destination; const char *src = source; while(n--) { *dest++ = *src++; //unitary operator calcul from right to left } } int vGenerateRandomValue(int max) { int r; //srand( (unsigned int)time(0) ); r = rand() % max + 1; // return 1 - max return r; } #define MAXN 10 int main() { int x[MAXN]; int buffer[MAXN]; int i; int n; int max = 100; for(n = 1; n <= MAXN ; n++) { printf(" n= %d ",n); for( i = 0; i <= n - 1; i++ ) { x[i] = vGenerateRandomValue(max) - 1; //0 - 9 printf(" %d", x[i]); } printf(" sorted: "); memcpyMy(buffer,x,n*sizeof(int)); //store original dates for later test mergeSort(x,n); for( i = 0; i <= n - 1; i++ ) { printf(" %d", x[i]); } printf(" "); #define s sorted #define c conform assert(s(x, n)); assert(c(x, buffer,n)); } return 0; }