数据结构与C语言实现(十二)——排序合集

来源:互联网 发布:c语言中char是什么意思 编辑:程序博客网 时间:2024/06/10 21:06
#include <stdio.h>#include <stdlib.h>#define MAXSIZE 200#define MAXDATA 65535int arry[MAXSIZE];struct HNode{int data[MAXSIZE + 1];int size;int num;};typedef struct HNode* Heap;void Print(){for (int i = 0; i < MAXSIZE; i++)printf("%d  ", arry[i]);putchar('\n');}void Init(){for (int i = 0; i < MAXSIZE/2; i++)arry[i] = i;for (int i = MAXSIZE - 1; i >= MAXSIZE/2; i--)arry[i] = 300 - i;}void Insert_Sort(int arry[], int N){Init();int i;for (int p = 1; p < N; p++)//拿了一手牌,一张一张摸牌{int Tmp = arry[p];for (i = p; i > 0 && arry[i - 1] > Tmp; i--)//i > 0 && arry[i - 1],任意不满足都退出循环arry[i] = arry[i - 1];//找到i的下标后,向后移动挪出一个位置arry[i] = Tmp;//i下标存放的数字就是Tmp}}void Shell_Sort(int arry[],int N){Init();int D;int i;Heap H;for (D = N / 2; D > 0; D /= 2)//进行D间隔排序,直到间隔为1{for (int p = D; p < N; p++)//从D开始,往后一个一个来{int Tmp = arry[p];for (i = p; i > D && arry[i - D] > Tmp; i-=D)//注意,这里是间隔的核心,每次和D间隔之前的那个比较//从手上的最后一张牌数起,和D间隔之前的那个数字比较 ,直到手里牌的某一张(下标为i-1)小于或等于Tmparry[i] = arry[i - D];//找到i的下标后,向后移动挪出一个位置arry[i] = Tmp;//i下标存放的数字就是Tmp}}}//用最大堆实现堆排序Heap Create_Heap(){Init();int i,j;Heap H = (Heap)malloc(sizeof(struct HNode));printf("创建的堆为——");H->data[0] = MAXDATA;for (i = 1; i < MAXSIZE + 1; i++){H->data[i] = arry[i - 1];}//for (i = 0; i <= MAXSIZE; i++)//{//printf("%d  ", H->data[i]);//}H->num = MAXSIZE + 1;H->size = MAXSIZE;return H;}Heap Build_Heap(){int child, parent;Heap H = Create_Heap();for (int i = H->size / 2; i > 0; i--)//从倒数第二行开始调整{int temp = H->data[i];for (parent = i; parent * 2 <= H->size; )//破坏循环的条件是孩子到了堆的外面{child = parent * 2;if ((H->data[child + 1] > H->data[child])&&(child != H->size))child++;//如果右儿子比较大,那么右儿子++//父亲和儿子身份对调if (temp < H->data[child]){H->data[parent] = H->data[child];parent = child;}else{break;}}H->data[parent] = temp;}return H;}int Delete_Heap(Heap H){int child, parent;int ans = H->data[1];H->data[1] = H->data[H->size];int temp = H->data[1];H->size--;for (parent = 1; parent * 2 <= H->size;)//注意这里是小于等于{child = parent * 2;if ((H->data[child + 1] > H->data[child]) && (child != H->size))child++;//如果右儿子比较大,那么右儿子++//父亲和儿子身份对调if (temp < H->data[child]){H->data[parent] = H->data[child];parent = child;}else{break;}}H->data[parent] = temp;return ans;}void Heap_Sort(int arry[], int N){Heap H = Build_Heap();for (int i = N - 1; i >= 0; i--){arry[i] = Delete_Heap(H);}}//归并,将两个已经排序好的数组合成一个排序好的数组void Merge(int arry[], int temp[],int L,int R,int RightEnd){int LeftEnd = R - 1;int tmp = L;int Num = RightEnd - L + 1;//计算元素总个数//如果两边都没到终点,那么选取小的那个优先放入中间数组while (L <= LeftEnd && R <= RightEnd){if (arry[L] <= arry[R]) temp[tmp++] = arry[L++];else{temp[tmp++] = arry[R++];}}while (L <= LeftEnd)//如果左边还没到终点temp[tmp++] = arry[L++];while (R <= RightEnd)//如果右边还没到终点temp[tmp++] = arry[R++];//从尾巴向前把值赋值会arry数组里,赋值多少次呢?赋值M次for (int i = 0; i < Num; i++, RightEnd--)arry[RightEnd] = temp[RightEnd];}void Merge1(int arry[], int temp[], int L, int R, int RightEnd){int LeftEnd = R - 1;int tmp = L;int Num = RightEnd - L + 1;//计算元素总个数   //如果两边都没到终点,那么选取小的那个优先放入中间数组while (L <= LeftEnd && R <= RightEnd){if (arry[L] <= arry[R]) temp[tmp++] = arry[L++];else{temp[tmp++] = arry[R++];}}while (L <= LeftEnd)//如果左边还没到终点temp[tmp++] = arry[L++];while (R <= RightEnd)//如果右边还没到终点temp[tmp++] = arry[R++];//从尾巴向前把值赋值会arry数组里,赋值多少次呢?赋值M次//for (int i = 0; i < Num; i++, RightEnd--)//arry[RightEnd] = temp[RightEnd];}//归并排序void m_Sort(int arry[], int tmp[], int L, int RightEnd){int Center;if (L < RightEnd)//L == RightEnd的时候,说明只有一个元素{//分而治之Center = (L + RightEnd) / 2;m_Sort(arry, tmp, L, Center);//前半个进行排序m_Sort(arry, tmp, Center + 1, RightEnd);//对后半个进行排序Merge(arry, tmp, L, Center + 1, RightEnd);}}void Merge_Sort(int arry[],int N){Init();int *tmpA;tmpA = (int*)malloc(N * sizeof(int));if (tmpA != NULL){m_Sort(arry, tmpA, 0, N - 1);free(tmpA);}else printf("Error:空间不足。");}//函数作用是在某步长下,一次从头到尾的归并void Merge_pass(int arry[],int tmp[],int N,int length){int i,j;//i + length * 2 < N;已经不够做一次完整的两边等长的归并for (i = 0; i + length * 2 < N; i += 2*length){// i, i + length,i + 2*length -1,分别是头,中间,尾巴Merge(arry, tmp, i, i + length,i + 2*length -1 );}//破坏循环的条件是已经不能做等长的归并,那么应该做一次从当前到最后的归并。//比如前面是4个和4个归并,那最后一个可能是4个和3个的归并if (i + length < N)Merge(arry, tmp, i, i + length, N - 1);//前面是4个和四个的归并,那很可惜,这里连四个都没有,所以直接末尾保留else{for (j = i; j < N; j++)tmp[j] = arry[j];}}//函数作用是对整个数组进行若干次变步长的归并void Merge_Sort2(int arry[], int N){Init();int length = 1;int *tmpA;tmpA = (int*)malloc(N * sizeof(int));if (tmpA != NULL){while (length < N){Merge_pass(arry, tmpA, N, length);length *= 2;//Merge_pass(tmpA, arry, N, length);//length *= 2;}free(tmpA);}else printf("Error:空间不足。");}void swap(int a[], int i,int j){int temp;temp = a[i]; a[i] = a[j]; a[j] = temp;}void swap1(int a,int b){int temp;temp = a; a = b; b = temp;}//快速排序void QuickSort(int arry[],int left,int right){int i, last;if (left >= right) return;swap(arry, left, (left + right) / 2);//把左边调整到中间//last始终指向要被准备被换的那个元素的前一个last = left;for (i = left + 1; i <=right; i++){if (arry[i] < arry[left])swap(arry, ++last, i);//比枢纽点小,就自己跟自己换//比枢纽点大,last就不动,停在上一个比枢纽点小的位置上//直到再发现一个比枢纽点小的,那就last后移一位,恰好是比枢纽点大的//恰好实现小的和大的一次交换//last最后指向的是最后一个比枢纽点小的//所以把枢纽点和last替换,last的位置就是枢纽点应该待的位置}swap(arry, left, last);QuickSort(arry, left, last - 1);//检查枢纽点前面的集合QuickSort(arry, last + 1, right);//检查枢纽点后面的集合//为什么last不用变?因为last就在它最终应该在的位置上}void Quick_Sort(int arry[],int N){QuickSort(arry, 0, N - 1);}int main(){Init();Print();Insert_Sort(arry, MAXSIZE);printf("插入排序的结果是————————————\n");Print();Shell_Sort(arry, MAXSIZE);printf("希尔排序的结果是————————————\n");Print();Heap_Sort(arry, MAXSIZE);printf("堆排序的结果是————————————\n");Print();int ans[MAXSIZE];Merge_Sort(arry, MAXSIZE);printf("递归归并排序的结果是————————————\n");Print();Merge_Sort2(arry, MAXSIZE);printf("非递归归并排序的结果是————————————\n");Print();Init();Quick_Sort(arry, MAXSIZE);printf("快速排序的结果是————————————\n");Print();return 0;}

阅读全文
0 0
原创粉丝点击