插入排序算法总结

版权声明:本文为博主原创文章,转载时请注明文章出处和作者! https://blog.csdn.net/sb985/article/details/79778573

注:我排序所用的数组list的第一个即list[0],只用于存放临时交换数据,不参与数组元素的存储所以数据是从list[1]开始存储的
常见排序算法总结

1.插入排序

直接插入排序

在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使这n个数也是排好顺序的。如此反复循环,直到全部排好顺序

 /*  Input:  Unsort list
   Output: Sorted list
   1.traverse from 2 to end of List
        1.1 if current element is smaller than the former
        1.2 L.key[0] <- current Element
        1.3 put the former one back one step
        1.4 put back these which is bigger than current element -L.key[0]-
            before L.key[i-1] successively 
        1.5 put L.key[0] to correct place

 */
void InsertSort(int L[]){
    for(int i = 2;i <= L.length; ++i){
        int j;
        if(L[i] <= L[i-1]) {    //the former is bigger than the current one
            L[0] = L[i];        //复制为哨兵
            L[i] = L[i-1];      
            for(j = i-2;L[0] <= L[j]; --j){
                L[j+1] = L[j];  //记录后移
            }//endfor
            L[j+1] = L[0];  //插入到正确的位置
        }//endif
    }//endfor
}

希尔排序

大神希尔排序专题参考
先将整个待排序列分割成若干个子序列分别对每个子序列进行直接插入排序,待整个序列的记录"基本有序"时,在对全体记录进行一次直接插入排序.
其实就是每次按照一定的长度选取若干个元素组成子序列然后子序列内部直接插入排序,然后增量长度不断递减
这里写图片描述
第一次
分割子序列为(49,13),(38,27),(65,49),(97,55),(76,04)
子序列直接插入排序(13,49),(27,38),(49,65),(55,97),(04,75)
第一趟结果13,27,49,55,04 | 49,38,65,97,76
第二次
子序列(13,55,38,76),(27,04,65),(49,49,97)
子序列直接插入排序(13,38,55,76),(04,27,65),(49,49,97)
第二趟结果13,04,49 | 38,27,49 | 55,65,97,76
…..

/*
    Input: Unsort list and increment
    Output:Sorted list
    1.increment from dk to L's tail
        1.1 if current element is smeller than the former one in subsquence
        1.2 store current element in L.key[0]
        1.3 do directInsertSort to current subsequence to make it ordered
 */

void ShellInsert(int L[],int dk){
    //dk is the increment(两个元素的位置差)
    for(int i = dk+1;i <= L.length; ++i){
        if(L[i] <= L[i-dk]) {
            L[0] = L[i];
            int j;
            /*
               每次减dk是因为子序列中的元素之间间隔为dk
               对子序列中的元素进行直接插入排序,直接插入排序前n个元素已经有序

               在前n个有序的序列中从后向前找到第一个大于当前元素的元素
               与当前元素交换实现子序列的内部直接插入排序
             */
            for(j = i-dk;j > 0 && L[0] <= L[j];j-=dk){
                L[j+dk] = L[j];
            }//endfor
            //此处的j+dk是因为在执行完for循环后还会 j-=dk在判断,所以退出是就多减可了dk
            L[j+dk] = L[0];
        }//endif
    }//endfor
}

void ShellSort(int L[],int dlta[],int t){
    //按照增量序列dl[0]~dl[t-1]对顺序表L作希尔排序
    //dkta[]是增量表,t是要使用的增量个数
    for(int k = 0;k < t; ++k){
        ShellInsert(L,dlta[k]);
    }//endfor
}

折半插入排序

在直接插入排序中是把当前元素与前n个有序元素比较,判断应该插入的位置,如果前面的有序序列较长时,逐一比较会特别浪费时间,而折半插入排序在查找插入位置时可以节省大量时间,其思路就是折半查找的思路.
取低端low和高端high和中间m, m = (high+low)/2,如果currentElement < m;在[low,m)中找,否则在(m,high]中找,不断划分区间知道找到插入位置.

/*
    Input:Unsort list
    Output:Sorted list
    1.i from 2 to L's tail
        1.1 L.key[0] <- current element
        1.2 find region satisfied to insert(high < low, right now)
        1.3 put from high+1 to i-1 back one step
        1.4 L.key[high+1] <- L.key[0]
 */
void BInsertSort(int L[]){
    int high,low,m;
    for(int i = 2;i <= 10 ; ++i){
        L[0] = L[i];    //将L[i]暂存到L[0]
        low = 1;
        high = i-1;
        while(low <= high){
            m = (low + high)/2;
            if (L[0] <= L[m]) {
                high = m - 1;   //插入低半区
            } else {
                low = m + 1;    //插入高半区
            }
        }//endwhile
        //while退出时high<low,j-1位置是待插元素,high+1是插入位置
        for(int j = i-1;j >= high+1; --j){
            L[j+1] = L[j];//记录后移
        }//endfor
        L[high+1] = L[0];//插入
    }//endfor
}

表插入排序

可以参考:
1.https://www.cnblogs.com/hujunzheng/p/4677484.html
2.https://blog.csdn.net/zhangxiangdavaid/article/details/28127311

表插入排序是使用静态链表进行插入排序, 每次插入修改指针项, 通过指针项的链接顺序, 使静态链表有序.

//数据表类定义
const int SIZE = 100;       //静态链表最大容量
const int MAXINT = 10000;   //最大整数

template <class T>
struct StaListNode{
    T data;     //记录项
    int next;   //指针项
};
template <class T>
class StaticList {
    public:
        StaListNode<T> node[SIZE];
        int curlen; //链表实际长度
        StaticList();
        //~StaticList();
};
template <class T>
StaticList<T>::StaticList(){
    cout << "创建静态链表"<<endl;
    cout << "请输入静态链表的实际长度:"<<endl;
    cin  >>curlen;
    cout << "请输入各结点数量:"<<endl;
    node[0].data = MAXINT;
    node[0].next = 0;
    for(int i = 1;i <= curlen; ++i){
        node[i].next = 0;
        cin >> node[i].data;
    }//endfor
}
template <class T>
void StaListInsertSort(){
    StaticList<T> sl;
    int min,max;
    sl.node[0].next = 1;    //把第一个元素视为最小的
    sl.node[1].next = 0;    //初始化形成只有头结点的循环链表
    max = min = 1;

    for(int i = 2;i <= sl.curlen; ++i){
        //找到最小值并插入正确位置
        if(sl.node[i].data <= sl.node[min].data) {
            sl.node[0].next = i;    //首元素的next是最小值的位置
            //当前元素插入到最小的的前面
            sl.node[i].next  = min;
            min = i;                //min <-curPosition
        }//endif

        //找到最大值并插入正确位置
        if(sl.node[i].data >= sl.node[max].data) {
            sl.node[i].next = 0;    //最大元素的next是0
            sl.node[max].next = i;  //把当前元素插入到最大元素后
            max = i;                //max <-curPosition
        }//endif

        if(sl.node[i].data < sl.node[max].data && sl.node[i].data > sl.node[min].data) {
            int index1 = min,index2;
            while(sl.node[i].data >= sl.node[index1].data){
                //从最小值开始向后遍历(升序)找到插入位置
                index2 = index1;
                index1 = sl.node[index1].next;
            }//endwhile
            //index1是插入位置的下一个位置,插在第index2元素后
            sl.node[i].next = index1;
            sl.node[index2].next = i;
        }//endif
    }//endfor

    cout <<"表插入排序结果如下:"<<endl;
    T index = sl.node[0].next;
    while(index != 0){//最大值的next是0
        cout << sl.node[index].data <<"\t";
        index = sl.node[index].next;
    }//endwhile
    cout<<endl;
}

猜你喜欢

转载自blog.csdn.net/sb985/article/details/79778573