Skip to content

Latest commit

 

History

History
590 lines (429 loc) · 15.8 KB

第三节--排序算法.md

File metadata and controls

590 lines (429 loc) · 15.8 KB

第三节--排序算法

光栅处理的主要作用是将3D模型转换成能够被显示与屏幕的图像,并对图像进行修正和进一步美化处理,让展现在眼前的画面更为逼真与生动

一.认识排序

1.认识排序

"排序"(Sorting)就是指将一组数据,按特定规则调换位置,使数据具有某种顺序关系(递增或递减)。用以排序的依据被称为键(Key),它所含的值就称为"键值"。通常键值的数据类型有数值类型,中文字符串类型以及非中文字符串类型三种

在排序过程中,数据的移动方式可分为"直接移动"和"逻辑移动"两种。"直接移动"是直接交换存储数据的位置,而"逻辑移动"并不会移动数据存储的位置,仅改变指向这些数据的辅助指针的值

两者间的优劣在于直接移动会浪费许多时间进行数据的移动,而逻辑移动只要改变辅助指针指向的位置就能轻易达到排序的目的

二.冒泡排序法

1.过程简介

冒泡排序法又称为交换排序法,原理是从第一个元素开始比较相邻元素的大小,若大小顺序有误,则对调后再进行下一个元素的比较,仿佛气泡逐渐从水底冒升到上面上。如此扫描一次过后就可确保最后一个元素位于正确的顺序。接着再逐步进行第二次扫描,直到完成所有元素的排序关系为止

2.例子说明

下面使用55,23,87,62,16数列来演示排序过程

由此可知5个元素的冒泡排序法必须执行4(5-1)次扫描,第一次扫描需比较4(5-1)次,共比较了4+3+2+1=10次

3.程序说明

源程序:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author LQ6H

data = [16,25,39,27,12,8,45,63]

print("冒泡排序法 原始数据:")

for i in range(8):
    print("%3d" %data[i],end=" ")
print()

for i in range(7,0,-1):
    for j in range(i):
        if data[j]>data[j+1]:
            data[j],data[j+1] = data[j+1],data[j]
    print("第 %d 次排序后的结果是:" %(8-i),end=" ")

    for j in range(8):
        print("%3d" %data[j],end=" ")
    print()

print("排序后的结果为:")
for j in range(8):
    print("%3d" %data[j],end=" ")
print()

运行结果:

冒泡排序法 原始数据16  25  39  27  12   8  45  63 
 1 次排序后的结果是16  25  27  12   8  39  45  63 
 2 次排序后的结果是16  25  12   8  27  39  45  63 
 3 次排序后的结果是16  12   8  25  27  39  45  63 
 4 次排序后的结果是12   8  16  25  27  39  45  63 
 5 次排序后的结果是8  12  16  25  27  39  45  63 
 6 次排序后的结果是8  12  16  25  27  39  45  63 
 7 次排序后的结果是8  12  16  25  27  39  45  63 
排序后的结果为8  12  16  25  27  39  45  63 

三.选择排序法

1.过程简介

选择排序法(Selection Sort)也算是枚举法的应用,就是反复从未排序的数列中取出最小的元素,加入到另一个数列中,最后的结果即为已排序的数列。选择排序法可使用两种方式排序,一种为在所有的数据中,从大到小排序,将最大值放入第一个位置;另一种是从小到大排序,将最大值放入最后一个位置

2.例子说明

3.程序说明

源程序:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author LQ6H

def showdata(data):
    for i in range(8):
        print("%3d" %data[i],end=" ")
    print()

def select(data):
    for i in range(7):
        for j in range(i+1,8):
            if data[i] > data[j]:
                data[i],data[j] = data[j],data[i]
    print()

data = [16,25,39,27,12,8,45,63]
print("原始数据为:")
for i in range(8):
    print("%3d" %data[i],end=" ")

print("\n-----------------------------")
select(data)
print("排序后的数据为:")
for i in range(8):
    print("%3d" %data[i],end=" ")

运行结果:

原始数据为16  25  39  27  12   8  45  63 
-----------------------------

排序后的数据为8  12  16  25  27  39  45  63 

四.插入排序法

1.过程简介

插入排序法(Insert Sort)是将数组中的元素,逐一与已排序好的数据进行比较,前两个元素先排好,再将第三个元素插入适当的位置,所以这三个元素仍然是已排序好的,接着将第四个元素加入,重复此步骤,直到排序完成为止

2.例子说明

3.程序说明

源程序:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author LQ6H

SIZE = 8                     #定义数组大小

def showdata(data):
    for i in range(SIZE):
        print("%3d" %data[i],end=" ")
    print()

def insert(data):
    for i in range(1,SIZE):
        temp = data[i]
        no = i - 1
        while no>=0 and temp<data[no]:
            data[no+1] = data[no]
            no-=1
        data[no+1] = temp

def main():
    data = [16,25,39,27,12,8,45,63]
    print("原始数组是:")
    showdata(data)
    insert(data)
    print("排序后的数组是:")
    showdata(data)

if __name__ == '__main__':
    main()

运行结果:

原始数组是16  25  39  27  12   8  45  63 
排序后的数组是8  12  16  25  27  39  45  63 

五.希尔排序法

1.过程简介

"希尔排序法"是可以减少插入排序法中数据搬移的次数,以加速排序的进行。排序的原则是将数据区分成特定间隔的几个小区块,以插入排序法排完区块内的数据后再渐渐减少间隔的距离

2.例子说明

3.程序说明

源程序:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author LQ6H

SIZE = 8

def showdata(data):
    for i in range(SIZE):
        print("%3d" %data[i],end=" ")
    print()

def shell(data,size):
    k=1                                # 打印计数
    jmp=size//2

    while jmp!=0:
        for i in range(jmp,size):              #i为扫描次数,jmp为设置间距的位移量
            temp = data[i]
            j=i-jmp                            #以j来定位比较的元素

            while temp<data[j] and j>=0:
                data[j+jmp]=data[j]
                j=j-jmp
            data[jmp+j]=temp
        print("第%d次排序过程:" %k,end=" ")
        k+=1
        showdata(data)
        print("---------------------------")
        jmp=jmp//2      #控制循环的次数

def main():
    data = [16,25,39,27,12,8,45,63]
    print("原始数据是:")
    showdata(data)
    print("-------------------------------")
    shell(data,SIZE)

main()

运行结果:

原始数据是16  25  39  27  12   8  45  63 
-------------------------------
第1次排序过程12   8  39  27  16  25  45  63 
---------------------------
第2次排序过程12   8  16  25  39  27  45  63 
---------------------------
第3次排序过程8  12  16  25  27  39  45  63 

六.合并排序法

1.过程简介

合并排序法(Merge Sort)的工作原理是针对已排序好的两个或两个以上的数列(或数据文件),通过合并的方式,将其组合成一个大的且已排好序的数列(或数据文件)。步骤如下:

  1. 将N个长度为1的键值,成对地合并成1/2个长度为2的键值组
  2. 将N/2个长度为2的键值组,成对地合并成N/4个长度为4的键值组
  3. 将键值组不断地合并,直到合并成一组长度为N的键值组为止

2.例子说明

3.程序说明

源程序:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author LQ6H

# 9999为数列1的结束数字不列入排序
list1 = [20,45,51,88,9999]
# 9999为数列1的结束数字不列入排序
list2 = [98,10,23,15,9999]
list3 = []

def merge_sort():
    global list1
    global list2
    global list3

    # 先使用选择排序将两个数列排序,在进行合并
    select_sort(list1,len(list1)-1)
    select_sort(list2,len(list2)-1)

    print("\n第1个数列的排序结果为:",end=" ")
    for i in range(len(list1)-1):
        print(list1[i]," ",end=" ")

    print("\n第2个数列的排序结果为:", end=" ")
    for i in range(len(list2) - 1):
        print(list2[i], " ", end=" ")
    print()

    print("----------------------------------------------------------")

    My_Merge(len(list1)-1,len(list2)-1)

    print("----------------------------------------------------------")

    print("\n合并排序法的最终结果为:",end=" ")
    for i in range(len(list1)+len(list2)-2):
        print("%d" %list3[i],end=" ")


def select_sort(data,size):
    for base in range(size-1):
        small = base
        for j in range(base+1,size):
            if data[j]<data[small]:
                small = j
        data[small],data[base] = data[base],data[small]


def My_Merge(size1,size2):
    global list1
    global list2
    global list3

    index1 = 0
    index2 = 0

    for index3 in range(len(list1)+len(list2)-2):
        if list1[index1]<list2[index2]:   # 比较两个数列,其中数小的先存储到合并后的数列中
            list3.append(list1[index1])
            index1+=1
            print("此数字%d取自于第1个数列" %list3[index3])
        else:
            list3.append(list2[index2])
            index2+=1
            print("此数字%d取自于第2个数列" %list3[index3])

        print("目前的合并排序结果为:",end=" ")

        for i in range(index3+1):
            print(list3[i]," ",end=" ")
        print("\n")

merge_sort()

运行结果:

第1个数列的排序结果为20   45   51   88   
第2个数列的排序结果为10   15   23   98   
----------------------------------------------------------
此数字10取自于第2个数列
目前的合并排序结果为10   

此数字15取自于第2个数列
目前的合并排序结果为10   15   

此数字20取自于第1个数列
目前的合并排序结果为10   15   20   

此数字23取自于第2个数列
目前的合并排序结果为10   15   20   23   

此数字45取自于第1个数列
目前的合并排序结果为10   15   20   23   45   

此数字51取自于第1个数列
目前的合并排序结果为10   15   20   23   45   51   

此数字88取自于第1个数列
目前的合并排序结果为10   15   20   23   45   51   88   

此数字98取自于第2个数列
目前的合并排序结果为10   15   20   23   45   51   88   98   

----------------------------------------------------------

合并排序法的最终结果为10 15 20 23 45 51 88 98 

七.快速排序法

1.过程简介

快速排序又称分割交换排序法,是目前公认最佳的排序法,也是使用"分而治之"(Divide and Conquer)的方式,先在数据中找到一个虚拟的中间值,并按此中间值将所有打算排序的数据分为两部分。其中,小于中间值的数据放在左边,大于中间值的数据放在右边,再以同样的方式分别处理左,右两边的数据,直到排序完成为止。

操作与分割步骤如下:
假设有n项记录R,R,R......R其键值为KKKK

  1. 先假设K的值为第一个键值
  2. 从左向右找出键值K使得K>K
  3. 从右向左找出键值K使得K<K
  4. 如果i<j,那么K与K互换,并回到步骤2
  5. 若i>=j则将K与K交换,并以j为基准点分割成左右部分。然后针对左右两边进行步骤1至5,直到左半边键值等于右半边键值

2.例子说明

3.程序说明

源程序:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author LQ6H

import random

def inputarr(data,size):
    for i in range(size):
        data[i] = random.randint(1,100)

def showdata(data,size):
    for i in range(size):
        print("%3d" %data[i],end=" ")
    print()

def quick(d,size,lf,rg):
    # 第一项键值为d[lf]
    if lf<rg:
        lf_idx = lf+1
        while d[lf_idx]<d[lf]:
            if lf_idx+1 >size:
                break
            lf_idx+=1
        rg_idx = rg

        while d[rg_idx]>d[lf]:
            rg_idx-=1
        while lf_idx<rg_idx:
            d[lf_idx],d[rg_idx] = d[rg_idx],d[lf_idx]
            lf_idx+=1
            while d[lf_idx]<d[lf]:
                lf_idx+=1
            rg_idx-=1
            while d[rg_idx]>d[lf]:
                rg_idx-=1
        d[lf],d[rg_idx] = d[rg_idx],d[lf]

        for i in range(size):
            print("%3d" %d[i],end=" ")
        print()

        quick(d,size,lf,rg_idx-1)     # 以rg_idx为基准点分成左右两半以递归方式
        quick(d,size,rg_idx+1,rg)     # 分别为左右两半进行排序直至完成排序


def main():
    data = [0]*100
    size = int(input("请输入数列的大小(100以下):"))
    inputarr(data,size)
    print("你输入的原始数据是:")
    showdata(data,size)
    print("排序的过程如下:")
    quick(data,size,0,size-1)
    print("最终的排序结果为:")
    showdata(data,size)

main()

运行结果:

请输入数列的大小(100以下):10
你输入的原始数据是51  61  92  11  12   5  15  56  63  24 
排序的过程如下5  24  15  11  12  51  92  56  63  61 
  5  24  15  11  12  51  92  56  63  61 
  5  12  15  11  24  51  92  56  63  61 
  5  11  12  15  24  51  92  56  63  61 
  5  11  12  15  24  51  61  56  63  92 
  5  11  12  15  24  51  56  61  63  92 
最终的排序结果为5  11  12  15  24  51  56  61  63  92 

八.基数排序法

1.过程简介

基数排序法按比较的方向可分为最高位有先(Most Significant Digit First,MSD)和最低位优先(Least Significant Digit First,LSD)两种。MSD法是从最左边的位数开始比较,而LSD则是从最右边的位数开始比较

2.例子说明

3.程序说明

源程序:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author LQ6H

import random

def inputarr(data,size):
    for i in range(size):
        data[i] = random.randint(0,999)

def showdata(data,size):
    for i in range(size):
        print("%3d" %data[i],end=" ")
    print()

def radix(data,size):
    n = 1 # n为基数,从个位数开始排序
    while n<=100:
        temp = [[0]*100 for row in range(10)]
        for i in range(size):
            m = (data[i]//n)%10
            temp[m][i]=data[i]

        k=0
        for i in range(10):
            for j in range(size):
                if temp[i][j]!=0:
                    data[k] = temp[i][j]
                    k+=1
        print("经过%3d位数排序后:" %n,end=" ")
        showdata(data,size)
        n=10*n

def main():
    data = [0]*100
    size = int(input("请输入数列的大小(100以下):"))
    print("你输入的原始数据是:")
    inputarr(data,size)
    showdata(data,size)
    radix(data,size)

main()

运行结果:

请输入数列的大小(100以下):10
你输入的原始数据是518 278 781 726  52 589 490 764 662 142 
经过  1位数排序后490 781  52 662 142 764 726 518 278 589 
经过 10位数排序后518 726 142  52 662 764 278 781 589 490 
经过100位数排序后52 142 278 490 518 589 662 726 764 781