基于SeqList的商品管理系统

1.整体架构:
Ui (.h/.cpp) : 用户交互层
AppLogic (h/.cpp) : 应用逻辑层
DataAccess (h/.cpp) : 数据处理
main (.cpp) : 主函数入口

template<class T, int Maxsize>
SeqList{
private:
    T data[MaxSize];
    int length;
    T* IndexP[MaxSize];//按商品代号排序的指针数组
    T* NameP[MaxSize];//按商品名称排序的指针数组
    T* PriceP[MaxSize];//按商品价格排序的指针数组
    int pLength;
    //逻辑删除时,pLength--,因为data[MaxSize]数组中没有  物理删除数据,所以length永远都不会减小!!!
publicSeqList();
    SeqList(T a[], int n);
    int ListLength();
    T Get(int pos);
    int Locate(T item);
    void PrintSeqList();
    void Insert(int i, T item);
    T Delete(int i);
    T DeleteMin();
    void DeleteAllX(T x);
    void DeleteS2T(T s, T t);
    void DeleteRepeate();
    void partSort();
    void QuickSort(int l, int r);
    void Merge(SeqList<T, MaxSize> &seqList2);
    int GetpLength();//有效元素个数
    T IndexPAt(int i);//商品代号指针数组在下标为i上的元素
    void Append(T &t);//增
    void DeleteByIndex(int index);//按商品代号删除
    void DeleteByName(string name);//按商品名称删除
    void DeleteByPrice(double price);//按商品价格删除
    void UpdateByIndex(int index);//按商品代号更新
    void SearchByIndex(int index);//按商品代号二分查找
    void SearchByName(string name);//按商品名称二分查找
    void SearchByPrice(double price);//按商品价格二分查找
    void PrintByIndexOrder();//按商品代号遍历打印
    void PrintByNameOrder();//按商品名称遍历打印
    void PrintByPriceOrder();//按商品价格遍历打印
};

2.实例化时控制好MaxSize,防止栈溢出
模板类SeqList在实例化时,因为是线性表结构,内部是用数组int data[MaxSize]实现的,所以在实例化的时候是从栈中申请空间,故MaxSize不能设得太大,否则会导致栈溢出

3.SeqList中设置多个指针数组,实现多重排序

T* IndexP[MaxSize];//按商品代号排序的指针数组
T* NameP[MaxSize];//按商品名称排序的指针数组
T* PriceP[MaxSize];//按商品价格排序的指针数组
class Goods {
private:
    int Index;
    string Name;
    double Price;
    int Count;
    int PosOfIndexP;
    int PosOfNameP;
    int PosOfPriceP;
public:
    Goods();
    Goods(int index, string name, double price, int count);
    int GetIndex();
    string GetName();
    double GetPrice();
    int GetCount();
    int GetPosOfIndexP();
    int GetPosOfNameP();
    int GetPosOfPriceP();
    void SetPosOfIndexP(int pos);
    void SetPosOfNameP(int pos);
    void SetPosOfPriceP(int pos);
    void SetPrice(double price);
    void SetCount(int count);
    Goods& operator=(const Goods &g);
    bool operator>(const Goods &g);
    bool operator<(const Goods &g);
    bool operator>=(const Goods &g);
    bool operator<=(const Goods &g);
    bool operator==(const Goods &g);
    bool operator!=(const Goods &g);
    friend ostream& operator<<(ostream &o, Goods &g);
    friend istream& operator>>(istream &i, Goods &g);
};

4.在Goods类中设置在多重排序指针数组中的位置的变量,以实现逻辑删除;并使得删除时pLength–,而length保持永远不会减少,真正实现逻辑删除

int PosOfIndexP;//当前Goods g在IndexP指针数组中的位置
int PosOfNameP;//当前Goods g在NameP指针数组中的位置
int PosOfPriceP;//当前Goods g在PriceP指针数组中的位置

5.比较操作符的重载,赋值运算符的重载,输入/输出操作符的重载

6.增删改查的实现代码

//构造函数
//无参构造函数
template<class T, int MaxSize>
SeqList<T, MaxSize>::SeqList() {
    length = 0;
    pLength = 0;
}

//有参构造函数
template<class T, int MaxSize>
SeqList<T, MaxSize>::SeqList(T a[], int n) {
    if (n > MaxSize) {
        cerr << "参数非法";
        exit(1);
    }
    length = 0;
    pLength = 0;
    for (int i = 0; i < n; i++) {
        //*1,*2两步,避免野指针!!!
        data[length] = a[i];//*1
        int j;
        //找到正确位置,后面的指针向后移一位,本指针插入正确位置
        for (j = 0; j < pLength; j++) {
            if (a[i].GetIndex() < IndexP[j]->GetIndex()) {
                for (int k = pLength; k > j; k--) {
                    IndexP[k] = IndexP[k - 1];
                    IndexP[k]->SetPosOfIndexP(IndexP[k]->GetPosOfIndexP() + 1);
                }
                IndexP[j] = &data[length];//*2
                IndexP[j]->SetPosOfIndexP(j);
                break;
            }
        }
        //没有“正确”位置,本指针插入尾部
        if (j == pLength) {
            IndexP[j] = &data[length];
            IndexP[j]->SetPosOfIndexP(j);
        }
        for (j = 0; j < pLength; j++) {
            if (strcmp(a[i].GetName().c_str(), NameP[j]->GetName().c_str()) < 0) {
                for (int k = pLength; k > j; k--) {
                    NameP[k] = NameP[k - 1];
                    NameP[k]->SetPosOfNameP(NameP[k]->GetPosOfNameP() + 1);
                }
                NameP[j] = &data[length];
                NameP[j]->SetPosOfNameP(j);
                break;
            }
        }
        if (j == pLength) {
            NameP[j] = &data[length];
            NameP[j]->SetPosOfNameP(j);
        }
        for (j = 0; j < pLength; j++) {
            if (a[i].GetPrice() < PriceP[j]->GetPrice()) {
                for (int k = pLength; k > j; k--) {
                    PriceP[k] = PriceP[k - 1];
                    PriceP[k]->SetPosOfPriceP(PriceP[k]->GetPosOfPriceP() + 1);
                }
                PriceP[j] = &data[length];//*2
                PriceP[j]->SetPosOfPriceP(j);
                break;
            }
        }
        if (j == pLength) {
            PriceP[j] = &data[length];
            PriceP[j]->SetPosOfPriceP(j);
        }
        length++;
        pLength++;
    }
}

//求有效元素的个数
template<class T, int MaxSize>
int SeqList<T, MaxSize>::GetpLength() {
    return pLength;
}

//返回商品代号指针数组IndexP下标为i的元素
template<class T, int MaxSize>
T SeqList<T, MaxSize>::IndexPAt(int i) {
    return *IndexP[i];
}

//增删改查
//每次都把T添加到data数组尾部,并更新各个指针数组
template<class T, int MaxSize>
void SeqList<T, MaxSize>::Append(T &t) {
    data[length] = t;//*1.先将t复制给data尾部

    int i;
    for (i = 0; i < pLength; i++) {
        /*!!!!通过*1和*2两步将指针指向data数组中的元素,避免了因指向t的地址,而当临时变量t销毁时,
        本次插入的指针就乱指的情况!!!!*/
        if (t.GetIndex() < IndexP[i]->GetIndex()) {
            for (int j = pLength; j > i; j--) {
                IndexP[j] = IndexP[j - 1];
                IndexP[j]->SetPosOfIndexP(IndexP[j]->GetPosOfIndexP() + 1);
            }
            IndexP[i] = &data[length];//*2.将本次插入的指针指向data数组的元素
            IndexP[i]->SetPosOfIndexP(i);
            break;
        }
    }
    if (i == pLength) {
        IndexP[i] = &data[length];
        IndexP[i]->SetPosOfIndexP(i);
    }
    for (i = 0; i < pLength; i++) {
        if (strcmp(t.GetName().c_str(),NameP[i]->GetName().c_str()) < 0) {
            for (int j = pLength; j > i; j--) {
                NameP[j] = NameP[j - 1];
                NameP[j]->SetPosOfNameP(NameP[j]->GetPosOfNameP() + 1);
            }
            NameP[i] = &data[length];
            NameP[i]->SetPosOfNameP(i);
            break;
        }
    }
    if (i == pLength) {
        NameP[i] = &data[length];
        NameP[i]->SetPosOfNameP(i);
    }
    for (i = 0; i < pLength; i++) {
        if (t.GetPrice() < PriceP[i]->GetPrice()) {
            for (int j = pLength; j > i; j--) {
                PriceP[j] = PriceP[j - 1];
                PriceP[j]->SetPosOfPriceP(PriceP[j]->GetPosOfPriceP() + 1);
            }
            PriceP[i] = &data[length];
            PriceP[i]->SetPosOfPriceP(i);
            break;
        }
    }
    if (i == pLength) {
        PriceP[i] = &data[length];
        PriceP[i]->SetPosOfPriceP(i);
    }
    length++;
    pLength++;
}

//按商品代号删除,用二分查找提高效率
template<class T, int MaxSize>
void SeqList<T, MaxSize>::DeleteByIndex(int index) {
    int l = 0, r = pLength - 1, mid;
    while (l <= r) {
        mid = (l + r) / 2;
        if (IndexP[mid]->GetIndex() < index)
            l = mid + 1;
        else if (IndexP[mid]->GetIndex() > index)
            r = mid - 1;
        else {
            /*
            因为用了多个数组指针,所以进行物理删除时(即Delete(???))会使得数组指针中的指针发生偏移,
            故用逻辑删除(即只删除指针数组中的指针,而data数组中的数据不删除)
            进行多次逻辑删除,先删除NameP和PriceP数组中的指针,再删除IndexP数组中的指针
            */
            for (int i = IndexP[mid]->GetPosOfNameP(); i < pLength - 1; i++) {
                NameP[i] = NameP[i + 1];
                NameP[i]->SetPosOfNameP(NameP[i]->GetPosOfNameP() - 1);
            }
            NameP[pLength - 1] = NULL;
            for (int i = IndexP[mid]->GetPosOfPriceP(); i < pLength - 1; i++) {
                PriceP[i] = PriceP[i + 1];
                PriceP[i]->SetPosOfPriceP(PriceP[i]->GetPosOfPriceP() - 1);
            }
            PriceP[pLength - 1] = NULL;
            for (int i = mid; i < pLength - 1; i++) {
                IndexP[i] = IndexP[i + 1];
                IndexP[i]->SetPosOfIndexP(IndexP[i]->GetPosOfIndexP() - 1);
            }
            IndexP[pLength - 1] = NULL;
            pLength--;
            break;
        }
    }
    if (l > r)
        cout << "此商品不存在!" << endl;
}

//按商品名称删除,用二分查找提高效率
template<class T, int MaxSize>
void SeqList<T, MaxSize>::DeleteByName(string name) {
    int l = 0, r = pLength - 1, mid;
    while (l <= r) {
        mid = (l + r) / 2;
        if (strcmp(NameP[mid]->GetName().c_str(), name.c_str()) < 0)
            l = mid + 1;
        else if (strcmp(NameP[mid]->GetName().c_str(), name.c_str()) > 0)
            r = mid - 1;
        else {
            /*
            因为用了多个数组指针,所以进行物理删除时(即Delete(???))会使得数组指针中的指针发生偏移,
            故用逻辑删除(即只删除指针数组中的指针,而data数组中的数据不删除)
            进行多次逻辑删除,先删除IndexP和PriceP数组中的指针,再删除NameP数组中的指针
            */
            for (int i = NameP[mid]->GetPosOfIndexP(); i < pLength - 1; i++) {
                IndexP[i] = IndexP[i + 1];
                IndexP[i]->SetPosOfIndexP(IndexP[i]->GetPosOfIndexP() - 1);
            }
            IndexP[pLength - 1] = NULL;
            for (int i = NameP[mid]->GetPosOfPriceP(); i < pLength - 1; i++) {
                PriceP[i] = PriceP[i + 1];
                PriceP[i]->SetPosOfPriceP(PriceP[i]->GetPosOfPriceP() - 1);
            }
            PriceP[pLength - 1] = NULL;
            for (int i = mid; i < pLength- 1; i++) {
                NameP[i] = NameP[i + 1];
                NameP[i]->SetPosOfNameP(NameP[i]->GetPosOfNameP() - 1);
            }
            NameP[pLength - 1] = NULL;
            pLength--;
            break;
        }
    }
    if (l > r)
        cout << "此商品不存在!" << endl;
}

//按商品价格删除,用二分查找提高效率
template<class T, int MaxSize>
void SeqList<T, MaxSize>::DeleteByPrice(double price) {
    int l = 0, r = pLength - 1, mid;
    while (l <= r) {
        mid = (l + r) / 2;
        if (PriceP[mid]->GetPrice() < price)
            l = mid + 1;
        else if (PriceP[mid]->GetPrice() > price)
            r = mid - 1;
        else {
            /*
            因为用了多个数组指针,所以进行物理删除时(即Delete(???))会使得数组指针中的指针发生偏移,
            故用逻辑删除(即只删除指针数组中的指针,而data数组中的数据不删除)
            进行多次逻辑删除,先删除IndexP和NameP数组中的指针,再删除PriceP数组中的指针
            */
            for (int i = PriceP[mid]->GetPosOfIndexP(); i < pLength - 1; i++) {
                IndexP[i] = IndexP[i + 1];
                IndexP[i]->SetPosOfIndexP(IndexP[i]->GetPosOfIndexP() - 1);
            }
            IndexP[pLength - 1] = NULL;
            for (int i = PriceP[mid]->GetPosOfNameP(); i < pLength - 1; i++) {
                NameP[i] = NameP[i + 1];
                NameP[i]->SetPosOfNameP(NameP[i]->GetPosOfNameP() - 1);
            }
            NameP[pLength - 1] = NULL;
            for (int i = mid; i < pLength - 1; i++) {
                PriceP[i] = PriceP[i + 1];
                PriceP[i]->SetPosOfPriceP(PriceP[i]->GetPosOfPriceP() - 1);
            }
            PriceP[pLength - 1] = NULL;
            pLength--;
            break;
        }
    }
    if (l > r)
        cout << "此商品不存在!" << endl;
}

//按商品代号更新
template<class T, int MaxSize>
void SeqList<T, MaxSize>::UpdateByIndex(int index) {
    int l = 0, r = pLength - 1, mid;
    while (l <= r) {
        mid = (l + r) / 2;
        if (IndexP[mid]->GetIndex() < index)
            l = mid + 1;
        else if (IndexP[mid]->GetIndex() > index)
            r = mid - 1;
        else {
            double price;
            int count;
            cout << "请输入更新后的价格:";
            cin >> price;
            cout << "请输入更新后的库存:";
            cin >> count;
            string name = IndexP[mid]->GetName();
            T t(index, name, price, count);
            //更新价格时会导致新的价格排序,采用逻辑删除此结点,再添加一个新的结点来实现,这样比较简单!!!
            this->DeleteByIndex(index);
            this->Append(t);
            break;
        }
    }
    //不存在,则增加一条记录
    if (l > r) {
        string name;
        double price;
        int count;
        cout << "该商品不存在,输入其信息后会自动添加商品记录:" << endl;
        cout << "请输入商品名称:";
        cin >> name;
        cout << "请输入商品价格:";
        cin >> price;
        cout << "请输入商品库存:";
        cin >> count;
        Goods g(index, name, price, count);
        this->Append(g);
    }

}

//按商品代号二分查找
template<class T, int MaxSize>
void SeqList<T, MaxSize>::SearchByIndex(int index) {
    int l = 0, r = pLength - 1, mid;
    while (l <= r) {
        mid = (l + r) / 2;
        if (IndexP[mid]->GetIndex() < index)
            l = mid + 1;
        else if (IndexP[mid]->GetIndex() > index)
            r = mid - 1;
        else {
            cout << *IndexP[mid];
            break;
        }
    }
    if (l > r)
        cout << "此商品不存在!" << endl;
}

//按商品名称二分查找
template<class T, int MaxSize>
void SeqList<T, MaxSize>::SearchByName(string name) {
    int l = 0, r = pLength - 1, mid;
    while (l <= r) {
        mid = (l + r) / 2;
        if (strcmp(NameP[mid]->GetName().c_str(),name.c_str()) < 0)
            l = mid + 1;
        else if (strcmp(NameP[mid]->GetName().c_str(), name.c_str()) > 0)
            r = mid - 1;
        else {
            cout << *NameP[mid];
            break;
        }
    }
    if (l > r)
        cout << "此商品不存在!" << endl;
}

//按商品价格二分查找
template<class T, int MaxSize>
void SeqList<T, MaxSize>::SearchByPrice(double price) {
    int l = 0, r = pLength - 1, mid;
    while (l <= r) {
        mid = (l + r) / 2;
        if (PriceP[mid]->GetPrice() < price)
            l = mid + 1;
        else if (PriceP[mid]->GetPrice() > price)
            r = mid - 1;
        else {
            cout << *PriceP[mid];
            break;
        }
    }
    if (l > r)
        cout << "此商品不存在!" << endl;
}

//按商品代号打印
template<class T, int MaxSize>
void SeqList<T, MaxSize>::PrintByIndexOrder() {
    for (int i = 0; i < pLength; i++) {
        cout << *IndexP[i];
    }
}

//按商品名称打印
template<class T, int MaxSize>
void SeqList<T, MaxSize>::PrintByNameOrder() {
    for (int i = 0; i < pLength; i++) {
        cout << *NameP[i];
    }
}

//按商品价格打印
template<class T, int MaxSize>
void SeqList<T, MaxSize>::PrintByPriceOrder() {
    for (int i = 0; i < pLength; i++) {
        cout << *PriceP[i];
    }
}

7.文件读写,写入时,(注1)先第一行写一条pLength数据,记录有效元素个数,并按有效元素个数,(注2)按照IndexP指针数组,用IndexPAt(int i)操作,按顺序将有效的pLength个数据写入文件

void LoadData(SeqList<Goods, 10000> &myList, char* fileName) {
    int index;
    string name;
    double price;
    int count;
    ifstream in(fileName);
    if (!in.is_open()) {
        cout << "Error opening file!";
        exit(1);
    }
    int num;
    in >> num;
    if (num == 0) {
        in.close();
        return;
    }
    while (!in.eof()) {
        in >> index >> name >> price >> count;
        Goods g(index, name, price, count);
        myList.Append(g);
    }
    in.close();
}

void SaveData(SeqList<Goods, 10000> &myList, char* fileName) {
    ofstream out(fileName);
    if (!out.is_open()) {
        cout << "Error opening file!";
        exit(1);
    }
    int n = myList.GetpLength();
    out << n << endl;//第一行写总共有多少个有效数据
    for (int i = 0; i < n - 1; i++) {
        out << myList.IndexPAt(i).GetIndex() << " " << myList.IndexPAt(i).GetName() << " " <<
            myList.IndexPAt(i).GetPrice() << " " << myList.IndexPAt(i).GetCount() << endl;
    }
    //最后一行特殊化处理,不能写入换行!!!
    out << myList.IndexPAt(n - 1).GetIndex() << " " << myList.IndexPAt(n - 1).GetName() << " " <<
        myList.IndexPAt(n - 1).GetPrice() << " " << myList.IndexPAt(n - 1).GetCount();
    out.close();
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值