スクラッチデータ構造(II)規則的な配列

定義により、特定の順序で配列内の要素の全ての順列の順序配列されています。どんなに多くの要素が挿入されているか、規則配列要素は、自動的に適切な位置に挿入されていません。ここでは、達成しなければならない規則的な配列の固定長です。

I.秩序配列COrderArrayクラス

整然とした配列を達成するために、配列を最初に達成されるべき機能を検討する必要があります。
配列を初期化するには1.コンストラクタを、指定された長さの配列が与えられました。
2.データ、最も重要な機能を挿入し、データを自動的に並んで順番に挿入されています。
指定された値を検索3.、整然とした配列が特定の値を見つけることは非常に簡単です非常に重要な機能を持っています。
アレイは通常順序付けられた配列添字アクセスと同じになるように前記指定された位置を検索し、この要素に対応する、機能[]添字演算子オーバーロードされています。
5.位置にある要素を削除します。
6.値指定された要素を削除します。
7.すべての要素を空にします。
8.この機能はまた、あなたが遭遇する可能性のあるブラシ対象アルゴリズムの問題の一種で、2つの注文の配列をマージします。

その理由は明らかに達成するための機能の種類について、あなたは関数宣言のヘッダファイルを書くために始めることができます。

#pragma once
#include "CArray.h"
class COrderArray ://依然是继承数组基类
    public CArray
{
public:
    COrderArray(int size);//构造函数
    void PushBack(int value);//插入数据
    void RemoveForValue(int value);//根据指定值删除数组元素
    void RemoveForPos(int pos);//根据指定位置删除数组元素
    int FindForValue(int value);//根据指定值查找数组元素
    int &operator[](int pos);
    //重载下标运算符,达到按位置操作数组元素的目的
    //重载下标运算符的时候,这里的返回值必须是引用类型
    void Clear();//清空所有元素
    void Merge(COrderArray& array);//合并两个有序数组
private:
    void _InsertElement(int value, int start);
    //因为在数组中插入值的时候会将该位置后的所有的元素都向后移一个位置,参数为插入值和后移的初始位
    //所以单独写一个私有函数来完成插入并后移的功能,防止函数体内容太多,该函数也是不能在外部去调用
    void _RemoveElement(int pos);
    //和上面同理,这个函数是用来删除数组中某个位置的元素,删除完成后把该位置后面的元素前移
    
    //注意:这两个函数和上面的的插入、删除函数的不同之处在于上面两个公有函数负责给用户调用
    //并且实现用什么样的策略去删除或者插入,它们是内部调用下面的两个私有函数
    //而这两个私有函数只是是完成插入和删除的功能
};

配列CARRAY基本クラスの他のメンバ関数とメンバ変数が定義されている、ここでは書きません。

具体的な実装クラス2 .COrderArray

1.コンストラクタ
が固定長の順序付けられた配列である、コンストラクタは、与えられたn個が必要であるため、その後アレイの容量をnに設定されています

COrderArray::COrderArray(int size)
{
    m_Capacity = size;
    mp_Array = new int[m_Capacity];
}

2の要素に挿入
各々の規則配列を挿入位置考慮すべき要素を挿入し、アレイ全体が依然として挿入後に順序付けられていることを確認してください。だから、挿入し、すでに配列要素のサイズ比較を持っているために、現在の要素の前の要素を挿入する必要があります。配列比較方法は、最小の要素を比較開始から、すなわち、採用することができます。
しかし、これは規則的な配列であるので、シーケンシャルモードを比較することは非常に面倒だと思われる、ここでの最適な使用の二分法です。即ち、第1初期位置と終了位置、及び素子の2つの中間の位置を決定します。挿入される要素は、中間要素よりも大きい場合、中間位置、現在の再設定するスタートビットを入れ、その後、新たな中間位置を再計算し、次に中間位置とを比較します。利点は、適切な挿入位置を見つけるためにすぐにあります。

//插入元素,判断元素大小来决定其应该在数组中位置
void COrderArray::PushBack(int value)
{
    //数组元素个数已经达到数组最大容量,直接返回
    if (m_Size == m_Capacity)
    {
        return;
    }

    //二分查找
    int start = 0;
    int end = m_Size;
    int mid = (start + end) / 2;
    while (1)
    {
        //数组还没有元素的时候,直接插入
        if (m_Size == 0)
        {
            mp_Array[m_Size] = value;
            break;
        }
        //循环跳出的条件,即mid与首尾之一相等
        if (mid==start||mid==end)
        {
            if (mp_Array[mid] > value)//如果最后一次循环时,mid位置的元素大于插入位置的元素
            {
                _InsertElement(value, mid);//对当前mid位置,调用插入元素的函数
                break;
            }
            //若最后一次循环时,mid位置元素小于插入位置的元素
            //对mid位置后面的一个位置,调用插入元素的函数   
            _InsertElementvalue, mid + 1);
            
            break;
        }
        //二分法,比较插入元素和中间元素的大小,然后改变mid的值
        if (mp_Array[mid] > value)//插入元素比中间元素小,end改为mid,mid根据新的end更新一下
        {
            end = mid;
            mid = (start + end) / 2;
        }
        else//插入元素比中间元素大,start改为mid,mid根据新的start更新一下
        {
            start = mid;
            mid = (start + end) / 2;
        }
    }
    m_Size++;
}

二分法プロセスは段階的に描かれた紙の上に、より適している、このプロセスを理解するのは簡単です。
実現の単なる機能ではちょうど、要素が位置を検索するために挿入する必要があります挿入サイクルの終わりにも挿入し、挿入位置を完了するには、_InsertElement(値、半ば)と呼ばれるように、実際には、挿入を完了しませんでしたすべての要素は、移動後の背後にいました。
次のように** _ InsertElement機能は次のとおりです。**

//在数组中要插入的元素位置之后的所有元素进行后移
void COrderArray::_InsertElement(int value, int pos)
{
    for (int i = m_Size; i > pos; i--)
    {
        mp_Array[i] = mp_Array[i - 1];
    }
    mp_Array[pos] = value;
}

ここでのみ、バックいずれかにすべての要素を移動させるためのループを挿入位置を必要とし、新しい要素を挿入します。

前記要素指定された値の検索
バイナリ検索を使用して、値を見つけるために、上記の方法および構成要素に類似します。

//根据值查找,二分查找,和上面的插入类似
int COrderArray::FindForValue (int value)
{
    int start = 0;
    int end = m_Size;
    int mid = (start + end) / 2;
    while (mid != start && mid != end)
    {
        if (mp_Array[mid] == value)
        {
            return mid;
        }
        if (mp_Array[mid] > value)
        {
            end = mid;
            mid = (start + end) / 2;
        }
        else
        {
            start = mid;
            mid = (start + end) / 2;
        }
    }
    if (mp_Array[mid] == value)
    {
        return mid;
    }
}

ルックアップ要素指定された位置
、実際に配列インデックスの関数であり、添え字が同一であるので、この場所は、関数を作成できませんが、添字演算子オーバーロード。動的配列を書き込む前にもこの機能を追加することができます。

int &COrderArray::operator[](int pos)
{
    if (pos > m_Size || pos < 0)
    {
        return mp_Array[0];
    }
    return mp_Array[pos];
}

戻り値は、参照型であるが、インデックスは、範囲指標の外にある場合、好ましくは、境界チェックで構成されている過負荷添字演算子は、配列の最初の要素を返します。

5. [すべての要素
と同様の動的配列要素空要素の現在の数がゼロにのみ必要。

//清空所有元素
void COrderArray::Clear()
{
    m_Size = 0;
}

6.に基づいて要素を削除する場所を指定し
、自動的に削除される要素を覆うようにだけ削除する必要があるが、1つの前の位置に移動させ、指定された位置に応じて削除された配列要素の位置の背後にあるすべての要素。フロント_RemoveElement(INT POS)関数機能に書き込まする要素を削除して、前方に移動した後、要素の場所を指定することで、このすべては、直接この関数を呼び出すと考えることができます。
** _ RemoveElement(int型POS)を次のように**

//删除操作,把删除的数后面每一个元素向前移动一个位置
void COrderArray::_RemoveElement(int pos)
{
    if (pos >= 0 && pos < m_Size)
    {
        for (int i = pos; i < m_Size; i++)
        {
            mp_Array[i] = mp_Array[i + 1];
        }
        m_Size--;
    }
}

指定された場所に応じて要素関数を削除します。

//根据指定位置删除元素
void COrderArray::RemoveForPos(int pos)
{
    _RemoveElement(pos);
}

指定された値は、要素の削除
まず、配列の要素を削除するために指定された値に指定された値の配列をそれが発見されたままで、それはルックアップ機能指定された値の前に直接書き込むことができ、戻り位置を受信するために変数を使用し、後ですることができ_RemoveElement(int型POS)関数の前で見られる呼び出します。

//根据指定值删除元素
void COrderArray::RemoveForValue(int value)
{
    int pos = FindForValue(value);
    _RemoveElement(pos);
}

8. 2つのソート配列マージ
順序付きマージ二つの配列を達成するために、思考のいくつかの方法があり、このオーバーヘッドが比較的大きい、組み合わせパッケージにソートされた配列を新しいオブジェクトを使用することです。そこでここでは最初の規則的な配列と第一及び第二の配列が変化していないにマージされた第2の規則的な配列を選択します。だから、関数のパラメータは、第二の規則的な配列でなければなりません。
そのマージ(COrderArray&tempArray)を
参照されCOrderArrayとの使用に注意してください。関数パラメータのクラスオブジェクトは、通常時に参照を使用する場合、参照コピーコンストラクタの使用は呼び出すことはありませんので、しかし、プログラムのコストを削減することができ、元のオブジェクトの直接操作。
そこには、新たなポインタのうちのオブジェクトに含まれている場合一方、参照によってパラメータを渡すために使用されなければなりません。渡された値は、オブジェクトのコピーを生成しますので、デストラクタは自動的に最後に実行されます、当初の目標は、新たなオフの外にポインタを削除します。プロセスの終了時に、1がデストラクタを呼び出しますが、エラーを実行しますが、これと同じポインタを複製削除します。パラメータは、オブジェクトのコピーを生成していないとして参照すること、それはデストラクタを呼び出すことはありません。オブジェクト自体が動的に作成された変数ではない場合はもちろん、ない値は、問題の多くを通過しました。
主なアイデアは、新しい配列に最初に小さなサイズ、より順番に二つの配列をマージして、アウト失い続けています。
ここでは固定長の配列を作成することであるため、新しい、より大きなメモリ空間を開く必要がありますので、それは2つの配列の容量の和の大きさであるので、ここから前方に組み合わせる合併は良いはずです。

//合并两个有序数组
void COrderArray::Merge(COrderArray& tempArray)
{
    //开一个新的内存来存储合并后的数组,首先需要计算新的内存需要多大
    int tempArrayCapacity = tempArray.getCapacity();
    int newCapacity = tempArrayCapacity + m_Capacity;
    int* newSpace = new int[newCapacity];

    //因为原来数组的元素有可能没有满
    //所以要从两个数组当前size的位置开始合并
    //tempsize即两个数组的size之和
    //pos是合并的时候的一个索引,每取出来一个元素,就放到newSpace[pos],并-1,到0的时候就合并完
    int tempArraySize = tempArray.getSize();
    int tempSize = tempArraySize + m_Size;
    int pos = tempSize - 1;//索引要-1

    //开始合并
    while (pos >= 0)
    {
    //如果第一个数组元素个数不为0才进行比较
        if (m_Size != 0)
        {
            //第一个数组元素大于传参进来的数组元素
            //或者第二个数组元素索引已经比较到0
            //第一个数组的元素放进新开的内存空间,然后size-1
            if (mp_Array[m_Size - 1] >= tempArray[tempArraySize - 1])
            {
                newSpace[pos] = mp_Array[m_Size - 1];
                m_Size--;
            }
            else
            {
                newSpace[pos] = tempArray[tempArraySize - 1];
                tempArraySize--;
            }
        }else//如果第一个数组元素个数已经为0,直接把另一个数组的元素按顺序放进来,不需要再进行比较
        {
            newSpace[pos] = tempArray[tempArraySize - 1];
            tempArraySize--;
        }
        pos--;
    }
    //清理掉要合并数组的原来的内存
    //把size设置为新的合并后的size
    //数组容量设置为新的容量
    //指针要指向新的存放数据的内存空间
    delete[] mp_Array;
    m_Size = tempSize;
    m_Capacity = newCapacity;
    mp_Array = newSpace;
}

ここでは、規則的な配列のすべての機能が完成達成するために、次の主な機能は、この規則的な配列呼び出すことです。

三つの主な機能Array.cpp

主な機能は、あなたが挿入されたデータが順序付けられている参照して、2つの注文の配列をマージすることができる2つの主要な規則配列オブジェクトを作成し、データを挿入することです。

#include<iostream>
using namespace std;
#include "COrderArray.h"
using namespace std;
int main()
{
    int n;
    cin >> n;

    //COrderArray* oArray = new COrderArray(n);
    COrderArray oArray(n);
    COrderArray oArray2(n);
    //插入第一个数组的数据
    for (int i = 0; i < n; i++)
    {
        int temp;
        cin >> temp;
        oArray.PushBack(temp);
    }
    //插入第二个数组的数据
    for (int i = 0; i < n; i++)
    {
        int temp;
        cin >> temp;
        oArray2.PushBack(temp);
    }
    oArray.Print();//打印数组
    
    oArray.Merge(oArray2);//合并两个数组
    oArray.Print();//重新打印
    return 0;
}
输入数据:
6
9 4 6 11 5 8
7 10 6 18 2 4

输出数据:
print all date :
4
5
6
8
9
11

合并数组后的输出数据:
print all date :
2
4
4
5
6
6
7
8
9
10
11
18

上の秩序配列のこの実現には、この場所は以前と同じようにint型の配列としてあり、そしてより多くの機能を実現するために、それはまた拡張に開放されて、テンプレートを使用していませんでした。最後に、すべてのファイルのコード。

すべてのソースコードファイル

次のようにすべてのコードCOrderArray.hファイルは次のとおりです。

#pragma once
#include "CArray.h"
class COrderArray ://依然是继承数组基类
    public CArray
{
public:
    COrderArray(int size);//构造函数
    void PushBack(int value);//插入数据
    void RemoveForValue(int value);//根据指定值删除数组元素
    void RemoveForPos(int pos);//根据指定位置删除数组元素
    int FindForValue(int value);//根据指定值查找数组元素
    int &operator[](int pos);
    //重载下标运算符,达到按位置操作数组元素的目的
    //重载下标运算符的时候,这里的返回值必须是引用类型
    void Clear();//清空所有元素
    void Merge(COrderArray& array);//合并两个有序数组
private:
    void _InsertElement(int value, int start);
    //因为在数组中插入值的时候会将该位置后的所有的元素都向后移一个位置,参数为插入值和后移的初始位
    //所以单独写一个私有函数来完成插入并后移的功能,防止函数体内容太多,该函数也是不能在外部去调用
    void _RemoveElement(int pos);
    //和上面同理,这个函数是用来删除数组中某个位置的元素,删除完成后把该位置后面的元素前移
    
    //注意:这两个函数和上面的的插入、删除函数的不同之处在于上面两个公有函数负责给用户调用
    //并且实现用什么样的策略去删除或者插入,它们是内部调用下面的两个私有函数
    //而这两个私有函数只是是完成插入和删除的功能
};

次のようにすべてのコードCOrderArray.cppファイルは次のとおりです。

#include<iostream>
#include "COrderArray.h"
COrderArray::COrderArray(int size)
{
    m_Capacity = size;
    mp_Array = new int[m_Capacity];
}

//在数组中要插入的元素位置之后的所有元素进行后移
void COrderArray::_InsertElement(int value, int pos)
{
    for (int i = m_Size; i > pos; i--)
    {
        mp_Array[i] = mp_Array[i - 1];
    }
    mp_Array[pos] = value;
}

//插入元素,判断元素大小来决定其应该在数组中位置
void COrderArray::PushBack(int value)
{
    if (m_Size == m_Capacity)
    {
        return;
    }

    //二分查找
    int start = 0;
    int end = m_Size;
    int mid = (start + end) / 2;
    while (1)
    {
        //数组还没有元素的时候,直接插入
        if (m_Size == 0)
        {
            mp_Array[m_Size] = value;
            break;
        }
        //循环跳出的条件,即mid与首尾之一相等
        if (mid==start||mid==end)
        {
            if (mp_Array[mid] > value)
            {
                _InsertElement(value, mid);
                break;
            }
            _InsertElement(value, mid + 1);
            break;
        }
        //大小判别,然后改变mid的值进行二分
        if (mp_Array[mid] > value)
        {
            end = mid;
            mid = (start + end) / 2;
        }
        else
        {
            start = mid;
            mid = (start + end) / 2;
        }
    }
    m_Size++;
}

//根据值查找,二分查找,和上面的插入类似
int COrderArray::FindForValue (int value)
{
    int start = 0;
    int end = m_Size;
    int mid = (start + end) / 2;
    while (mid != start && mid != end)
    {
        if (mp_Array[mid] == value)
        {
            return mid;
        }
        if (mp_Array[mid] > value)
        {
            end = mid;
            mid = (start + end) / 2;
        }
        else
        {
            start = mid;
            mid = (start + end) / 2;
        }
    }
    if (mp_Array[mid] == value)
    {
        return mid;
    }
}

//删除操作,把删除的数后面每一个元素向前移动一个位置
void COrderArray::_RemoveElement(int pos)
{
    if (pos >= 0 && pos < m_Size)
    {
        for (int i = pos; i < m_Size; i++)
        {
            mp_Array[i] = mp_Array[i + 1];
        }
        m_Size--;
    }
}

//根据指定位置删除元素
void COrderArray::RemoveForPos(int pos)
{
    _RemoveElement(pos);
}

//根据指定值删除元素
void COrderArray::RemoveForValue(int value)
{
    int pos = FindForValue(value);
    _RemoveElement(pos);
}
//重载下标运算符
int &COrderArray::operator[](int pos)
{
    if (pos > m_Size || pos < 0)
    {
        return mp_Array[0];
    }
    return mp_Array[pos];
}
//清空所有元素
void COrderArray::Clear()
{
    m_Size = 0;
}
//合并两个有序数组
void COrderArray::Merge(COrderArray& tempArray)
{
    //开一个新的内存来存储合并后的数组,首先需要计算新的内存需要多大
    int tempArrayCapacity = tempArray.getCapacity();
    int newCapacity = tempArrayCapacity + m_Capacity;
    int* newSpace = new int[newCapacity];

    //从两个数组当前size的位置开始合并
    int tempArraySize = tempArray.getSize();
    int tempSize = tempArraySize + m_Size;
    int pos = tempSize - 1;
    while (pos >= 0)
    {
        if (m_Size != 0)
        {
            if (mp_Array[m_Size - 1] >= tempArray[tempArraySize - 1]|| tempArraySize==0)
            {
                newSpace[pos] = mp_Array[m_Size - 1];
                m_Size--;
            }
            else
            {
                newSpace[pos] = tempArray[tempArraySize - 1];
                tempArraySize--;
            }
        }else
        {
            newSpace[pos] = tempArray[tempArraySize - 1];
            tempArraySize--;
        }
        pos--;
    }
    delete[] mp_Array;
    m_Size = tempSize;
    m_Capacity = newCapacity;
    mp_Array = newSpace;
}

次のようにすべてのコードArray.cppファイルは次のとおりです。

#include<iostream>
using namespace std;
#include "COrderArray.h"
using namespace std;
int main()
{
    int n;
    cin >> n;

    //COrderArray* oArray = new COrderArray(n);
    COrderArray oArray(n);
    COrderArray oArray2(n);
    //插入第一个数组的数据
    for (int i = 0; i < n; i++)
    {
        int temp;
        cin >> temp;
        oArray.PushBack(temp);
    }
    //插入第二个数组的数据
    for (int i = 0; i < n; i++)
    {
        int temp;
        cin >> temp;
        oArray2.PushBack(temp);
    }
    oArray.Print();//打印数组
    
    oArray.Merge(oArray2);//合并两个数组
    oArray.Print();//重新打印
    return 0;
}

おすすめ

転載: www.cnblogs.com/nsytsqdtn/p/11387654.html