参考:《数据结构与面向对象程序设计》(C++版)Michael Main等编著
sequence类与bag类不一样,bag类删除一个元素可以直接将最后一个元素取代即可,但是在sequence中,删除一个元素需要保持原来的顺序,所以需要将删除的元素后面的每一个元素向前挪动一个位置,并且 used-1.
sequence1.h:
#ifndef MAIN_SAVITCH_SEQUENCE_H
#define MAIN_SAVITCH_SEQUENCE_H
#include <cstdlib> //提供size_t
namespace main_savitch_3
{
class sequence
{
public:
typedef double value_type;
typedef std::size_t size_type;
static const size_type CAPACITY = 30;
sequence();
void start();
void advance();
void insert(const value_type& entry);
void attach(const value_type& entry);
size_type index() { return current_index; }
//删除当前数据项,索引是current_index
void remove_current();
//删除特定元素
void remove_target(const value_type& target);
size_type size() const;
bool is_item() const;
value_type current() const;
private:
value_type data[CAPACITY];
size_type used;
size_type current_index;
};
}
#endif
sequence.cpp:
#include "sequence1.h"
#include <iostream>
#include <cassert>
using namespace std;
namespace main_savitch_3
{
//构造函数
sequence::sequence()
{
used = 0;
current_index = 0;
}
//start()函数将当前项置为0
void sequence::start()
{
current_index = 0;
}
//每执行一次advance当前项向前移动一位
void sequence::advance()
{
++current_index;
}
//判断当前项是否有效,也就是是否超过used,注意current_index从0~used-1
bool sequence::is_item() const
{
//注意current_index从0~used-1,所以为used也是超出了
if (current_index >= used)
return false;
return true;
}
//返回当前项的元素
sequence::value_type sequence::current()const
{
assert(is_item());
return data[current_index];
}
//移除当前项,然后保持sequence,也就是后面序列全部往前挪动一位
void sequence::remove_current()
{
for (size_type i = 0; i <used; ++i)
{
//开始寻找和当前项一样的下表
if (i == current_index)
{
//然后从当前项开始,将下一项的呢内容复制给前一项,但是这里注意,这里没有销毁used-1那一项
for (size_type j = current_index; j < used-1; ++j)
data[j] = data[j + 1];
data[used - 1] = NULL;//将used-1项元素置为0
--used;
break;
}
}
}
//插入操作
void sequence::insert(const value_type& entry)
{
assert(size()< CAPACITY);
data[used++] = entry;//将其插入之后data[used]再自增
}
void sequence::attach(const value_type& entry)
{
/*...*/
}
sequence::size_type sequence::size() const
{
return used;
}
//删除特定的元素
void sequence::remove_target(const value_type& target)
{
for (size_type i = 0; i < used; ++i)
{
if (data[i] == target)
{
for (size_type j = i; j < used - 1; ++j)
{
data[j] = data[j + 1];
}
--used;
break;
}
}
}
}
sequence_demo.cpp
#include <iostream>
#include <cctype> //提供toupper
#include <cstdlib>//提供EXIT_SUCESS
#include "sequence1.h"
using namespace std;
using namespace main_savitch_3;
void get_numbers(sequence& numbers);
void show_numbers(sequence& numbers);
int main()
{
//定义numbers为sequence类
sequence numbers;
//执行start()
numbers.start();
//输入数据
get_numbers(numbers);
cout <<"输出 used 的大小:"<< numbers.size()<< endl;
cout << "输出当前项current_index的大小:" << numbers.index() << endl << endl;;
numbers.advance();
cout << "执行一次advance之后current_index的大小: " << numbers.index()<< endl;
numbers.remove_current();
cout << "删除了当前项之后后used的大小:" << numbers.size() << endl<<endl;
//删除元素12
cout << "尝试删除元素为15的元素" << endl;
numbers.remove_target(15);
cout << "删除一个元素之后used的大小:" <<numbers.size()<< endl<<endl;
//输出操作之后的结果
cout << "输出操作后sequence的结果" << endl;
show_numbers(numbers);
system("pause");
}
void get_numbers(sequence& numbers)
{
//
sequence::value_type input_number;
cout << "请输入一组有序的数,以-1结束:" << endl;
cin >> input_number;
//以输入的数据作为判断依据,那么在循环里面必然出现再次输入
while (input_number>=0)
{
//判断当前的已用空间是否达到CAPACITY
if (numbers.size() < numbers.CAPACITY)
//插入元素
numbers.insert(input_number);
else
cout << "哦,满了,容量满了!" << endl;
cin >> input_number;//再次输入
}
}
void show_numbers(sequence& numbers)
{
for (numbers.start(); numbers.is_item(); numbers.advance())
{
cout << numbers.current() <<" ";
}
cout << endl;
}
测试结果:
很明显,只是用main函数来测试会很容易打乱代码的逻辑,下面写一个程序交互测试代码
程序交互测试.cpp
#include<iostream>
#include<cctype> //提供toupper
#include<cstdlib>//提供EXIT_SUCESS
#include "sequence1.h"
using namespace std;
using namespace main_savitch_3;
void print_menu();
char get_user_command();
void show_sequence(sequence diaplay);
double get_number();
int main()
{
sequence test;
char choice;
cout << "I have initialized an empty sequence of real numbers" << endl;
do
{
print_menu();
choice = toupper(get_user_command());
switch(choice)
{
case '!':test.start();
break;
case '+':test.advance();
break;
case '?':if (test.is_item())
cout << "There is an item." << endl;
else
cout << "There is no current item." << endl;
break;
case 'C':if (test.is_item())
cout << "Current item is : " << test.current() << endl;
else
cout << "There is no current item." << endl;
break;
case 'P':show_sequence(test);
break;
case 'S':cout << "Size is " << test.size() << '.'<<endl;
break;
case 'I':test.insert(get_number());
break;
case 'A':test.attach(get_number());
break;
case 'R':test.remove_current();
cout << "The current item has been remove" << endl;
break;
case 'Q':cout << "Ridicule is the best test of the truth." << endl;
break;
default:cout << choice << " is invalid" << endl;
}
}
while (choice != 'Q');
return EXIT_SUCCESS;
}
void print_menu()
{
cout << endl;
cout << "The following choices are available:" << endl;
cout << " ! Activate the start() function" << endl;
cout << " + Activate the advance() function" << endl;
cout << " ? Print the result from the is_item() function<<endl"<<endl;
cout << " C Print The result from the current() function" << endl;
cout << " P Print a copy of the entire sequence" << endl;
cout << " S Print the result from the size() function" << endl;
cout << " I Insert a new number with the insert(...) function" << endl;
cout << " A Attach a new number with the attach(...) function" << endl;
cout << " R Activate the remove_current() function" << endl;
cout << " Q Quit this test program" << endl;
}
char get_user_command()
{
char command;
cout << "Enter choice:";
cin >> command;
return command;
}
void show_sequence(sequence display)
{
for (display.start(); display.is_item(); display.advance())
cout << display.current() << endl;
}
double get_number()
{
double result;
cout << "Please enter a real number for the sequence:";
cin >> result;
cout << result << " has been read." << endl;
return result;
}
提醒:
1、这里可以注意一下 toupper这个函数,它是<cctype>库中的一部分,目的是将小写转换成大写,所以对应地应该还有tolower() 将字母转换成小写
2、可以看到这个测试代码中输出show_sequence(display)没有使用引用传递,是因为使用引用传递会改变参数值,这是我们不希望看出现的。值传递会隐含一次复制操作,所以在时间上和空间上会消耗大一些
测试结果:
参考:《数据结构与面向对象程序设计》(C++版)Michael Main等编著