数据结构复习总结之插入排序(二)

今天开始学习插入排序,首先回顾一下冒泡排序和选择排序,以便进行比较:

冒泡排序:

每一次遍历都是比较前后两个元素的大小,把大的元素往后放,也就是当该次遍历完成后的效果就表中最大的元素置于表的最后,然后第二次遍历会把第二大元素放在倒数第二个位置,,,以此类推,依次把大的元素往后放即可完成排序。

选择排序

该算法的思想是把原序列分成两部分,有序(已排序)和无序(未排序部分)每次遍历都会去无序部分中找一个最小的元素与无序部分的第一个元素进行交换,也就是追加到有序序列的后边(放在有序序列的后边位置,不需要选位置)。比如第一次遍历时有序部分还没有,全都是无序的,就会从该序列中选一个最小的,与第一个元素进行交换,然后进行第二次遍历,,,

插入排序

该算法的思想也是把原序列分为两部分:有序和无序。首先第一个元素作为有序序列(选择排序最开始是全部当做无序序列处理)然后在遍历时把无序序列的第一个元素和该有序序列进行比较(它这里就不是追加了,是通过比较有序序列找一个合适的位置插入)具体插入方法是:首先比较该无序序列的第一个元素,和有序序列的最后一个进行比较,如果它比较小,就交换位置,然后和有序序列的倒数第二个进行比较,比它小就交换位置,直到最后找到合适的位置放置,,,

选择排序 VS 插入排序

也就是说选择排序每次遍历时都是从无序序列中找一个找一个最小的元素追加到有序序列的后边,不需要选位置,直接放到有序序列的最后(其实也就是在无序序列中找一个最小的和无序序列的第一个元素交换即可)
插入排序是每次遍历时都会找无序序列的第一个元素,然后是比较该元素和有序序列,在有序序列中找一个合适的位置进行插入;

一句话总结:
选择排序操作的是后边的无序序列;插入排序操作的是前面的有序序列

# -*- coding: utf-8 -*-
"""
Created on Sat May 26 09:16:57 2018

@author: Administrator
"""

#********************************插入排序*************************************
def Insert_sort(L):
    n=len(L)
    print("插入排序前:",L)
    for i in range(1,n):
        for j in range(i):
            if L[i]<L[j]:
                L[i],L[j]=L[j],L[i]
    print("插入排序后:",L)

Insert_sort([4,5,1,8,2,6,1])            

嗯,这个思路是错的,注意插入排序在比较的时候是把未排序部分的第一个元素与已排序部分从后往前进行比较!!!

# -*- coding: utf-8 -*-
"""
Created on Sat May 26 09:16:57 2018

@author: Administrator
"""

#********************************插入排序*************************************
#by_myselsf:
#*************这个是错的!!!
def Insert_sort1(L):
    n=len(L)
    print("版本1(错误!!):其实并不是插入排序的思想,比较的时候是从后往前,这里从前往后和无序序列的第一个元素进行比较的")
    print("插入排序前:",L)
    for i in range(1,n):
        for j in range(i):
            if L[i]<L[j]:
                L[i],L[j]=L[j],L[i]
    print("插入排序后:",L)

#by_teacher

def Insert_sort2(L):
    n=len(L)
    print("版本2:真正意义上的插入排序,选择无序序列的第一个元素需要从后往前和有序序列的元素进行比较,然后选择一个合适的位置插入进去")
    print("插入排序前:",L)
    for i in range(1,n):
        for j in range(i,0,-1):
            if L[j]<L[j-1]:
                L[j],L[j-1]=L[j-1],L[j]

    print("插入排序后:",L)   

def Insert_sort3(L):
    n=len(L) 
    print("版本3:插入排序方法2")
    print("插入排序之前:",L)
    for j in range(1,n): #需要遍历的次数
        i=j  #对于每一次遍历都需要把该无序序列的第一个值与有序序列进行比较(从后往前比较)
        while i>0: 
            if L[i]<L[i-1]:
                L[i],L[i-1]=L[i-1],L[i]
            i-=1
    print("插入排序后:",L)





if __name__=="__main__":
    Insert_sort1([6,2,1,4,9,5,0])            
    Insert_sort2([4,5,1,8,2,6,1])   
    Insert_sort3([3,1,9,4,2,7,4])         



****************************************分割线*********************************************
喔,刚才写代码的时候电脑简直卡死了,现在重新附上完整代码(冒泡排序,选择排序和插入排序)

# -*- coding: utf-8 -*-
"""
Created on Sat May 26 12:44:42 2018

@author: Administrator
"""

#***********************冒泡排序*************************
def Bubble_sort(L):
    n=len(L)
    print("冒泡排序之前:",L)
    for i in range(n-1):
        for j in range(n-1-i):
            if L[j]>L[j+1]:
                L[j],L[j+1]=L[j+1],L[j]
    print("冒泡排序之后:",L)

#***********************选择排序*************************
def Select_sort(L):
    n=len(L)
    print("选择排序之前:",L)
    for i in range(n-1):  #需要遍历的次数
        min=i  #先把最小值初始化为未排序序列的第一个元素
        for j in range(i,n):  #遍历后边未排序部分,找一个最小的追加到有序序列的后边
            if L[j]<L[min]:
                min=j
        L[i],L[min]=L[min],L[i]
    print("选择排序之后:",L)

#***********************插入排序*************************
def Insert_sort(L):
    n=len(L)
    print("插入排序之前:",L)
    for i in range(1,n):#最开始把第一个元素当做已排序的,对未排序序列进行遍历(从第二个元素到最后一个元素)
        for j in range(i,0,-1):
            if L[j]<L[j-1]:#比较该元素和前一个元素的大小,把未排序部分的第一个元素放到已排序部分的适当位置,其实就是交换啦
                L[j],L[j-1]=L[j-1],L[j]
            else: #由于已排序部分都是从小到大拍好的,如果该元素已经比已排序的某一个还大 说明就不用再动了  也就是无需再比较之前的元素了
                break  #跳出该层循环(也就是进行下一次遍历)
    print("插入排序之后:",L)
if __name__=="__main__":

    Bubble_sort([5,3,9,4,6,2,8,1])
    Select_sort([5,3,9,4,6,2,8,1])
    Insert_sort([5,3,9,4,6,2,8,1])


结果展示
冒泡排序之前: [5, 3, 9, 4, 6, 2, 8, 1]
冒泡排序之后: [1, 2, 3, 4, 5, 6, 8, 9]
选择排序之前: [5, 3, 9, 4, 6, 2, 8, 1]
选择排序之后: [1, 2, 3, 4, 5, 6, 8, 9]
插入排序之前: [5, 3, 9, 4, 6, 2, 8, 1]
插入排序之后: [1, 2, 3, 4, 5, 6, 8, 9]

关于插入排序还是想多说一句:
当某一次遍历时(也就是把未排序的第一个元素与前面已经排序部分进行比较,选择一个合适的为进行交换位置)需要注意的是只有该未排序部分元素比前面已经排序部分小时才进行交换,否则就不需要进行后续比较了,因为一旦该元素比前面某个元素大(那肯定比前面元素的前面元素还大)所以这个时候就需要break 跳出此次循环(也就是进行下一次遍历)

时间复杂度

最优时间复杂度O(n)(也就是当原序列是升序有序序列时)因为外层循环执行n次,每一次遍历内层循环只是执行一个else语句 所以复杂度总共是n
最坏时间复杂度O(n^2) (也就是当序列是降序)外层循环执行n次,内层循环也是执行n次(1,2,3,4,,,,n)(相当于1+2+3+4+,,,,+n=n^2复杂度)

稳定性

很明显插入排序是稳定的,不会改变原来序列的相对顺序。

猜你喜欢

转载自blog.csdn.net/jiaowosiye/article/details/80458894