C++在一個數組中實現多重表的插入的實現(數據結構與算法應用C++描述P109)

#pragma once
#ifndef __LISTMAP_H
#define __LISTMAP_H
#include <iostream>
#include <string>
//自定義一個錯誤報錯的類,繼承自length_error
class illeagleParameter : public std::length_error{
public:
    explicit illeagleParameter(const std::string &s):length_error(s){}
};

//自定義一個listMap用來存放n個線性表
template<typename T> class listMap
{
public:
    //類的構造函數初始化順序:
    //構造函數初始值列表只說明用於初始化成員的值,而不限定初始化的具體執行順序,成員
    //的初始化順序與它們在類定義中的出現順序一致:第一個定義的成員先被初始化,然後第二個
    //以此類推,構造函數初始值列表中初始值的前後位置關係不會影響實際的初始化順序,
    //所以在下面的初始化的時候,element是先於length,如果你要使用element(new T[length])
    //那麼就會出問題,因爲length這個時候還沒被初始化,所以你的length值不是listSize*elementSize!!!
    //注意,在參數初始化的順序,如果不清楚,就不要去寫element(new T[listSize*element])這種
    //因爲如果你不確定length和element誰先被初始化,如果length先被初始化是沒問題的,但是
    //如果element先被初始化就完蛋了,因爲此時的length是一個不確定的值,所以這個時候要注意
    //爲了以防萬一,我們就不使用不確定的元素去初始化,直接使用已知的。
    listMap(int listSize=1000,int elementSize=1000):front(new T[listSize+2]),last(new T[listSize+2]),
    length(listSize * elementSize),element(new T[listSize*elementSize]){
        front[0] = last[0] = -1;
        front[listSize+1] = last[listSize+1] = length - 1;
        //放兩個邊界主要是爲了好處理,左右內存空間還有沒有空的問題,
        //如果你不放一個邊界的話,那麼在查找左邊或右邊有沒有空的時候
        //就不容易找到終止條件,所以你在最後一個位置放一個邊界,如果
        //極限情況下,全滿的時候,你的std-1的last和std的front就是
        //相等的。
        for(int i = 1; i <= listSize;++i){
            front[i] = last[i] = -1+elementSize*(i-1);
        for(int i = 0; i != length; ++i)
            element[i] = 0;
        }
    }
    void insert(int i,int index,const T &theElement);//在第i個表的index處插入元素theEleme
    T get(int i,int index)const;
    int capacity()const;
    int getFront(int i)const;
    int getLast(int i)const;
    void printAllMemeber()const;
    ~listMap() {}

private:
    T *front;//表示每個線性數組的第一個元素的前面的位置(最開始元素的前一個位置)
    T *last;//表示每一個線性數組的最後一個元素的位置(索引)
    T *element;//存放所有元素的指針,每個數組中存放的大小是lastSize大小的
    int length;
};

#endif
#include "listMap.h"

template<typename T> void listMap<T>::insert(int i,int index,const T &theElement){
    bool rightFullFlag = 0,leftFullFlag = 0;
    int listSize = last[i] - front[i];//首先得到數組的大小
    //判讀索引是不是有效的
    if(index < 0 || index > listSize)//你要插入的元素的索引不能小於0也不能超過當前數組的大小
        throw illeagleParameter("the index must be right");
    //判斷完索引以後,我們需要去插入數據了
    /*
    1.第一步首先判斷本線性列表的空間有沒有滿
    */
    if(last[i] != front[i+1]){//如果當前這個數組還有空間
        //copy_back是將(first,last)元素拷貝到第三個迭代器指向的位置以及前邊的位置,詳情請看源碼
        //所以這樣可以很好的避免-1這個下標的處理(-1,last[i]]的元素拷貝
        //注意,這個copy_backward算法中的last表示的是尾後指針。所以需要last[i]+1;
        std::copy_backward(element+front[i]+index,element+last[i]+1,element+(last[i]+2));//從last[i]+1這個位置開始倒敘拷貝
        //拷貝完以後,我們需要插入數據,以及更改尾部指針的索引值
        element[front[i]+index+1] = theElement;
        last[i]++;
    }else{//如果內存空間已經被利用完了的話,那麼先搜索右邊的空間有沒有有剩餘的
        int j = i+1;//現在j爲i的右邊的第一個數組
        while(last[j] == front[j+1]){//如果右邊的數組空間也被利用完了
            //那麼就繼續向右邊開始搜索,但是搜索之前要注意一點,先判斷有沒有到最右邊的終點
            if(last[j] == length-1)//如果到了終點,好的,退出,然後往左查找
            {
                rightFullFlag = 1;
                break;//退出,開始從i的左端搜索
            }
            j++;//如果沒有達到終點的話,我們繼續向右查找
        }
        if(rightFullFlag == 0){//如果右邊有空間,
            std::copy_backward(element+front[i]+index,element+last[j]+1,element+last[j]+2);
            //接下來需要把轉移的數組進行下標的一個變換,因爲位置發生變換了
            //首先i的尾元素的指針的索引值要加1
            element[front[i]+index+1] = theElement;
            last[i]++;
            //剩下的他們的首前和尾部指針的索引值都加1就好了,也就是順移
            for(int k = i+1;k <= j;k++){
                front[k]++;last[k]++;
            }
        }else{//如果右邊滿了的話,那好,去左邊找新的內存空間
            j = i-1;//j爲i左邊第一個數組
            while(last[j] == front[j+1]){
                if(last[j] == -1){
                    leftFullFlag=1;//左邊也滿了,這個時候報錯就好了
                    std::cout<<"\nthere is no space to insert"<<std::endl;
                }
                j--;//往左邊找數組
            }
            if(leftFullFlag==0){
                std::copy(element+front[j]+1,element+front[i]+index+2,element+front[j+1]);
                //改變一些front和last的值
                //首先改變front[i]的值
                front[i]--;
                //接着順移一些front和last的值
                for(int k = i-1;k != j;--k){
                    last[k]--;//往左移動一下
                    front[k]--;//往左移動一下
                }
            }
        }
    }
}
template<typename T> T listMap<T>::get(int i,int index)const{
    return element[front[i]+index+1];//因爲front[i]表示的第一個元素的
    //前一個位置,所以查找元素的時候需要加1。

}
template<typename T> int listMap<T>::capacity()const{
    return length;
}

template<typename T> int listMap<T>::getFront(int i)const{
    return front[i];
}

template<typename T> int listMap<T>::getLast(int i)const{
    return last[i];
}
template<typename T> void listMap<T>::printAllMemeber()const{
    for(int i = 0; i != length; ++i)
        std::cout<<element[i]<<",";
}
int main()
{
    listMap<int> a(5,5);
    /*
    std::cout<<"the inist is\n";
    for(int i = 1; i <= 5;++i)
        std::cout<<"font["<<i<<"] is "<<a.getFront(i)<<" and last["
        <<i<<"]"<<" is "<<a.getLast(i)<<std::endl;
    std::cout<<std::endl;
    */
    for(int i = 0;i != 5;++i){
        a.insert(1,i,i*10+1);
        a.insert(2,i,i*10+2);
        a.insert(3,i,i*10+3);
        a.insert(4,i,i*10+4);
    }   
    for(int i = 1; i <= 5;++i)
        std::cout<<"font["<<i<<"] is "<<a.getFront(i)<<" and last["
        <<i<<"]"<<" is "<<a.getLast(i)<<std::endl;
    for(int i = 0;i != 5;++i)
        std::cout<<"get(1,"<<i<<") is "<<a.get(1,i)<<std::endl;
    std::cout<<std::endl;
    for(int i = 0;i != 5;++i){
        std::cout<<"get(2,"<<i<<") is "<<a.get(2,i)<<std::endl;
    }
    std::cout<<"\nafter the operator a.insert(1,0,100) the a is\n";
    a.insert(3,0,100);
    for(int i = 1; i <= 5;++i)
        std::cout<<"font["<<i<<"] is "<<a.getFront(i)<<" and last["
        <<i<<"]"<<" is "<<a.getLast(i)<<std::endl;
    a.printAllMemeber();
    for(int i = 0;i != 5;++i)
        std::cout<<"get(1,"<<i<<") is "<<a.get(1,i)<<std::endl;
    std::cout<<std::endl;
    for(int i = 0;i != 5;++i){
        std::cout<<"get(2,"<<i<<") is "<<a.get(2,i)<<std::endl;
    }

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章