340 likes | 586 Views
烟台职业学院精品课. 数据结构 (JAVA 版 ). www.YT_JAVA.com. 1. 2. 3. 4. 5. 何谓排序. 交换排序. 选择排序. 插入排序. 合并排序. 第八章 排序. 8 . 1 排序. 排序是将一组杂乱无章的数据重新排列成按照关键字有序的序列 排序算法的稳定性 如果有两个数据元素 ri 和 rj , 他们关键字 ki 等于 kj ,且排序前 ri 位于 rj 之前。若排序后,元素 ri 仍在 rj 之前,则称这样的排序算法是稳定的,否则就是不稳定的。
E N D
烟台职业学院精品课 数据结构(JAVA版) www.YT_JAVA.com
1 2 3 4 5 何谓排序 交换排序 选择排序 插入排序 合并排序 第八章 排序
8.1 排序 • 排序是将一组杂乱无章的数据重新排列成按照关键字有序的序列 • 排序算法的稳定性 如果有两个数据元素ri 和rj ,他们关键字ki等于 kj,且排序前ri位于rj之前。若排序后,元素ri仍在rj之前,则称这样的排序算法是稳定的,否则就是不稳定的。 • 内部排序与外部排序 内部排序:在待排序的数据序列中,元素的个数较少,排序整个过程所有的元素都保留在内存。 外部排序:待排序的数据很多,排序过程中数据要不断的内外存数据交替存取。 这里我们重点介绍的是内部排序 • 排序算法的性能评价 算法的时间复杂度:算法执行中,数据的比较次数、移动次数与数据个数的关系 算法的空间复杂度:算法执行中,除待排序数据本身所占用的内存空间外,需要附加内存空间与数据元素个数的关系
交换排序 冒泡排序 (Bubble Sort) 快速排序 (Quick Sort) 8.2 交换排序
8.2.1 冒泡排序 • 排序方法 将相邻的两个数据按关键字进行比较。若反序则交换,经一趟排序后,最大的值移到最后的位置,再对上面的元素重复刚才的操作,直到剩下一个元素为止。 • 算法分析 该算法最好的情况是已排序好的数据,只需一趟排序即可,比较次数为n,没有移动。最坏情况是反序的数据序列,需要n-1趟排序,比较次数和移动次数都是Ο(n2)因此,此算法的时间复杂度是Ο(n2)。
8.2.1 冒泡排序 • 实例
8.2.1 冒泡排序 • 程序实现public static void BubbleSort(int Index) { int i,j,k; //循环计数变量 boolean Change; //数据是否有改变 int Temp; //数据暂存变量 for (j = Index ; j>1; j--) //外层循环 { Change = false; //设置为数据未改变 for (i=0;j<j-1;j++) //内层循环 { //比较两数值 if(Data[i+1]<Data[i])
8.2.1 冒泡排序 { // 交换两数值 Temp = Data[i+1]; Data[i+1] = Data[i]; Data[i] = Temp; Change = true; //设置数据已改变 } } if(Change) //如果数据已改变则输出结果 { //打印目前排序状况 System.out.print("Current Sorting Result :"); for(k=0;k<Index;k++) System.out.print(" "+Data[k]+" "); System.out.println(""); } } }
8.2.2 快速排序 • 算法思想在待排序的数据中选一个数据作为基准,由序列的两边交替地向中间比较、交换,使得所有比基准小的元素都处于序列的左端,比基准大的元素都处于序列的右端,这样序列就被划分成两个子序列。再对两个子序列分别进行同样的操作,直到子序列的长度为1为止。 • 实例
8.2.2 快速排序 • 程序实现public static void QuickSort(int left,int Right,int Index) { int i,j,k; //循环计数变量 int Pivot; //枢纽变量 int Temp; //暂存变量 i=Left; //设定左指针 j=right+1; //设定右指针 Pivot=Data[Left]; //取最左边的元素 if (i<j) { do { do //从左往右找比Pivot大的值 { i++; } while ( Data[i]<=Pivot&&i<=Right); do //从右往左找比Pivot小的值 { j— }while(Data[j]>=Pivot&&j.Left);
8.2.2 快速排序 if(i<j) //交换Data[i]和Data[j] { Temp=Data[i]; Data[i]=Data[j]; Data[j]=Temp; } while(i>j); if(i>j) { Temp=Data[lefe]; //交换Data[Left]和Data[j] Data[Left]=Data[j]; Data[j]=Temp; //打印目前排序结果 System.out.print(“Current sorting result;”); for(k=0;k<Index;k++) { System,out.print(“”+Data[k]+””); } System,out.println(“”); } QuickSort(Left,j-1,Index); //排序左半边 QuickSort(j+1,Right,Index); //排序右半边 } }
8.2.2 快速排序 • 算法分析 快速排序是目前平均性能较好的一种排序方法。时间复杂度为Ο(nlog2n)。最好情况是,每趟排序后将序列分成两个长度相同的子序列。最坏情况是,当序列已排好序。此时时间复杂度为Ο(n2),比直接插入排序还慢。 快速排序是不稳定的算法,另外它是递归算法,所以运行时,系统需要设立一个工作栈。
选择排序 简单选择排序 (Sinple Selection Sort) 堆排序 (Heap Sort) 8.3 选择排序
8.3.1 简单选择排序 • 算法思想 假设待排序的数据序列有n个元素,第一趟,比较n个元素,选择关键字最小的元素,跟第一个元素交换;第二趟,在余下的n-1个元素中选择关键字次小的元素与第二个数据交换……经过n-1趟排序就完成。 • 实例
8.3.1 简单选择排序 • 程序实现Public static void selectsort(int index) { Int I,j,k; //循环计数变量 Int minvalue; //最小值变量 Int intdexmin; //最小值下标变量 Int temp; //暂存变量 For(i=o;i<index -1;i++) { MinValue=32767; //目前最小数值 IndexMin=0; //存储最小数值的下标量 for (i=0;I<Index;j++) { If(Data[j]<MinValue) //找到最小值 { MinValue=data[j]; //存储最小值 IndexMin=j; }
8.3.1 简单选择排序 Temp=Data[i] //交换两数值 Data[i]=Data[IndexMin]; Data[IndexMin]=Temp; } System.out.print(“Current sorting result:”); For(k=0;k<Index;k++); System.out.print(“ ”+Data[k]+” ”); System.out.print(“ ”); } } • 算法分析 简单选择排序的比较次数与数据的初始排列无关。其时间复杂度为Ο(n2),是不稳定的排序方法。
8.3.2 堆排序 • 堆的定义 堆是一棵完全二叉树,堆排序用的就是“大根堆”。 大根堆的条件是:完全二叉树中所有非终端结点的值均不小于其左孩子和右孩子结点的值。 • 建立堆 初始堆:
8.3.2 堆排序 调整5后:
8.3.2 堆排序 调整32后:
8.3.2 堆排序 调整50后:
8.3.2 堆排序 调整10后:
8.3.2 堆排序 • 利用堆排序先建一个”大根堆”,将根结点与最后一个结点交换,然后对前n-1个数据进行筛选,重复将它调整为一个大根堆,反复重复操作直至排序结束. • 算法分析 堆排序的时间复杂度为Ο(nlog2n);是不稳定的排序方法;空间复杂度为Ο(1)。
8.3.2 堆排序之建立堆程序 • //建立堆 public static void cerateheap (int root,int index) { int I, j; //循环计数变量 int temp; //暂存变量 int finish; //判断是否建立完成 j=2*root; //子节点的Index temp=heap[root]; //暂存堆的Root 值 finish=0; //欲设堆建立尚未完成 while(j《=index——finish= =0》 { If(j〈index〉 //找最大的子节点 If(heap[j]heap[j+1]) J++; if(temp>=heap[j]) finish=1; //堆建立完成 Else { Heap[j/2]=temp; //父节点=目前节点 J=2*j; } } Heap[j/2]=temp; //父节点=Root值 }
8.3.2 堆排序之堆排序程序 Public static void heapsort(int index) { Int I,j,temp; //将二叉树转成堆 For(i=(index/2);i>=1;i--;) Createheap(I,index); //开始进行堆建设 for(i=index/2);i>=1;i--) { Temp=heap[i+1]; //堆的Root值和最后一个值交换 Heap[i+1]=heap[1]; Heap[i]=temp; createheap(1,i); //对其余数值重建堆 //打印堆的处理过程 system.out.print(“sorting process:”; for(j=1;j<=index;j++) system.out.print(“ “+heap[j]+” “); system.out.print(“ “); } }
8.4 插入排序 3 1 2 二叉树排序 Binary_tree Sort 直接插入排序Straight Insertion Sort 希尔排序 Shell Sort
8.4.1 直接插入排序 • 排序方法 从第二个元素开始依次将每个元素插入到前面有序的序列中,经过n-1次完成。 • 实例
8.4.1 直接插入排序 • 程序实现public static void insertsort (int index) { int I, j, k; //循环计数变量 int insertnode; //欲插入数据变量 for(I=1;I<index;I++) //依次插入数值 { insertnode=data[I]; //设定欲插入的数值 j=I-1; //欲插入数组的开始位置 //找适当的位置 while (j>=0&&insertnode<data[j]) { data[j+1]=data[j]; j--; } data[j+1]=insertnode; //将数值插入 //打印目前排序结果 system.out.print(“current sorting result :”); for(k=0;k<index;k++) system.out.print(“ “+data[k]+” “); system.out.println(“ “); } }
8.4.1 直接插入排序 • 算法分析 直接插入排序的时间复杂度为Ο(n2);空间复杂度为Ο(1);当数据已经有序情况下为最好的情况,时间复杂度为Ο(n)。 • 算法改进对于直接插入排序算法的基础上,从减少比较和移动的次数着眼,改进算法.例如,由于插入排序的基本操作是在一个有序表中进行查找和插入的,这个查找可以利用”折半查找”来实现.
8.4.2 希尔排序(Shell Sort) • 算法思想先将整个待排序数据序列分割成为若干子序列分别进行插入排序,待整个数据“基本有序”时,再对全体记录进行一次直接插入排序。 • 算法分析 Shell Sort排序是以插入排序进行排序,由于插入排序对已排好的部分会快速处理。Shell Sort排序时间复杂度为Ο(nlog2n),空间复杂度为Ο(1),不稳定的排序算法。
8.5 合并排序 1.算法思想合并排序就是将两个有序的数据序列合并,生成 一个有序的序列,又称两路归并。 两路归并排序算法描述如下: • 将初始序列看成是由n个长度为1的已排序子序列组成; • 反复将两个子序列合并成一个已排序的序列; • 重复上步,直到合并成一个序列. 2.算法分析 合并排序算法是可用来处理大量数据的排序,属于稳定的排序,空间复杂度是Ο(n),时间复杂度为Ο(nlog2n)。
8.5 合并排序 • 实例
Thank You ! www.themegallery.com