排序实验报告

  • 格式:doc
  • 大小:83.00 KB
  • 文档页数:9

实验五 排序

实验目的: 掌握几种排序的思想及算法

问题分析:

(一)直接插入排序

1. 排序思想

将待排序的记录Ri,插入到已排好序的记录表R1, R2 ,…., Ri-1中,得到一个新的、记录数增加1的有序表。 直到所有的记录都插入完为止。

设待排序的记录顺序存放在数组R[1…n]中,在排序的某一时刻,将记录序列分成两部分:

◆ R[1…i-1]:已排好序的有序部分;

◆ R[i…n]:未排好序的无序部分。

显然,在刚开始排序时,R[1]是已经排好序的。

2 . 算法实现

void straight_insert_sort(Sqlist R)

{ int i, j ;

for (i=2; i<=n; i++)

{ R[0]=R[i]; j=i-1; /*设置哨兵*/

while( LT(R[0].key, R[j].key) )

{ R[j+1]=R[j];

j--;

} /* 查找插入位置 */

R[j+1]=R[0]; /* 插入到相应位置*/

}

}

(二)希尔排序

1. 排序思想

① 先取一个正整数d1(d1

② 取新的增量d2

2. 算法实现

先给出一趟希尔排序的算法,类似直接插入排序。

void shell_pass(Sqlist R, int d)

/* 对顺序表L进行一趟希尔排序, 增量为d */

{ int j, k ;

for (j=d+1; j<=n; j++)

{ R[0]=R[j] ; /* 设置监视哨兵 */

k=j-d ;

while (k>0&<(R[0].key, R[k].key) )

{ R[k+d]=R[k] ; k=k-d ; }

R[k+d]=R[0] ; }

}

然后在根据增量数组dk进行希尔排序。

void shell_sort(Sqlist R, int dk[], int t)

/* 按增量序列dk[0 … t-1],对顺序表L进行希尔排序 */

{ int m ;

for (m=0; m

shll_pass(R, dk[m]) ;

}

增量序列取法

◆ 无除1以外的公因子;

◆ 最后一个增量值必须为1。

(三)简单选择排序

1. 排序思想

基本操作是:通过n-i次关键字间的比较,从n-i+1个记录中选取关键字最小的记录,然后和第i个记录进行交换,i=1, 2, … n-1 。

2. 算法实现

void simple_selection_sort(Sqlist R)

{ int i, j,k;

for (i=1; i

{ k=i ;

for (j=i+1; j<=n;j++)

if ( LT(R[j].key, R[k].key) ) k=j ;

if (k!=i) /* 记录交换 */

{ R[0]=R[k]; R[k]=R[i];

R[i]=R[0];

}

}

}

(四)堆排序

1. 排序思想

① 对一组待排序的记录,按堆的定义建立堆;

② 将堆顶记录和最后一个记录交换位置,则前n-1个记录是无序的,而最后一个记录是有序的;

③ 堆顶记录被交换后,前n-1个记录不再是堆,需将前n-1个待排序记录重新组织成为一个堆,然后将堆顶记录和倒数第二个记录交换位置,即将整个序列中次小关键字值的记录调整(排除)出无序区;

④ 重复上述步骤,直到全部记录排好序为止。

排序过程中,若采用小根堆,排序后得到的是递减序列;若采用大根堆,排序后得到的是递增序列。

堆的调整——筛选

⑴ 堆的调整思想

输出堆顶元素之后,以堆中最后一个元素替代之;然后将根结点值与左、右子树的根结点值进行比较,并与其中小者进行交换;重复上述操作,直到是叶子结点或其关键字值小于等于左、右子树的关键字的值,将得到新的堆。称这个从堆顶至叶子的调整过程为“筛选”,如图10-10所示。

⑵ 堆调整算法实现

void Heap_adjust(Sqlist R, int low, int high) /* R[low..high]中记录关键字除R[low].key均满足堆定义 */

/* 调整R[low]的位置使之成为小根堆 */

{ R[0]=R[low] ; /*临时保存调整点R[low] */

for (k=2*low; k<=high; k=k*2)

{ if ((k

k++ ; /* 选择左、右孩子中关键字的最小者 */

if ( LT(R[k].key, R[0].key) )

{ R[j]=R[k] ; low=k ; }

else break ;

}

R[j]=R[0] ;

}

2. 堆的建立

利用筛选算法,可以将任意无序的记录序列建成一个堆,设R[1],R[2], …,R[n]是待排序的记录序列。

将二叉树的每棵子树都筛选成为堆。只有根结点的树是堆。第⌊n/2⌋个结点之后的所有结点都没有子树,即以第n/2个结点之后的结点为根的子树都是堆。因此,以这些结点为左、右孩子的结点,其左、右子树都是堆,则进行一次筛选就可以成为堆。同理,只要将这些结点的直接父结点进行一次筛选就可以成为堆…。

只需从第n/2个记录到第1个记录依次进行筛选就可以建立堆。

3.堆排序算法实现

堆的根结点是关键字最小的记录,输出根结点后,是以序列的最后一个记录作为根结点,而原来堆的左、右子树都是堆,则进行一次筛选就可以成为堆。

void Heap_Sort(Sqlist R)

{ int i ;

for (i=n/2; i>0;ij--)

Heap_adjust(R, i , n) ; /*初始建堆*/

for (i=n; i>=1; i--)

{ R[0]=R[1] ; R[1]=R[i] ;

R[i]=R[0] ; /* 堆顶与最后一个交换 */

Heap_adjust(R, 1, i-1) ;

}

}

(五)快速排序

1. 排序思想

通过一趟排序,将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,再分别对这两部分记录进行下一趟排序,以达到整个序列有序。

2. 排序过程

设待排序的记录序列是R[s…t] ,在记录序列中任取一个记录(一般取R[s])作为参照(又称为基准或枢轴),以R[s].key为基准重新排列其余的所有记录,方法是:

◆ 所有关键字比基准小的放R[s]之前;

◆ 所有关键字比基准大的放R[s]之后。

以R[s].key最后所在位置i作为分界,将序列R[s…t]分割成两个子序列,称为一趟快速排序。

3. 一趟快速排序方法

从序列的两端交替扫描各个记录,将关键字小于基准关键字的记录依次放置到序列的前边;而将关键字大于基准关键字的记录从序列的最后端起,依次放置到序列的后边,直到扫描完所有的记录。 设置指针low,high,初值为第1个和最后一个记录的位置。

设两个变量i,j,初始时令i=low,j=high,以R[low].key作为基准(将R[low]保存在R[0]中) 。

① 从j所指位置向前搜索:将R[0].key与R[j].key进行比较:

◆ 若R[0].key≤R[j].key :令j=j-1,然后继续进行比较, 直到i=j或R[0].key>R[j].key为止;

◆ 若R[0].key>R[j].key :R[j]R[i],腾空R[j]的位置, 且令i=i+1;

② 从i所指位置起向后搜索:将R[0].key与R[i].key进行比较:

◆ 若R[0].key≥R[i].key :令i=i+1,然后继续进行比较, 直到i=j或R[0].key

◆ 若R[0].key

重复①、②,直至i=j为止,i就是R[0](基准)所应放置的位置。

4. 算法实现

⑴ 一趟快速排序算法的实现

int quick_one_pass(Sqlist R , int low, int high)

{ int i=low, j=high ;

R[0]=R[i] ; /* R[0]作为临时单元和哨兵 */

do {

while (LQ(R[0].key, R[j].key)&&(j>i))

j-- ;

if (j>i) { R[i]=R[j] ; i++; }

while (LQ(R[i].key, R[0].key)&&(j>i))

i++ ;

if (j>i) { R[j]=R[i] ; j--; }

} while(i!=j) ; /* i=j时退出扫描 */

R[i]=R[0] ; return(i) ;

}

⑵ 快速排序算法实现

当进行一趟快速排序后,采用同样方法分别对两个子序列快速排序,直到子序列记录个为1为止。

① 递归算法

void quick_Sort(Sqlist R , int low, int high)

{ int k ;

if (low

{ k=quick_one_pass(R, low, high);

quick_Sort(R, low, k-1);

quick_Sort(R, k+1, high);

} /* 序列分为两部分后分别对每个子序列排序 */

}

② 非递归算法

void quick_Sort(Sqlist R , int low, int high)

{ int k , stack[MAX_STACK] , top=0;

do { while (low

{ k=quick_one_pass(R,low,high);

stack[++top]=high ; stack[++top]=k+1 ;

/* 第二个子序列的上,下界分别入栈 */

high=k-1 ;

}

if (top!=0)

{ low=stack[top--] ; high=stack[top--] ; }