目录
第一章
第二章(时间/空间复杂度)
第三章
第四章
第五章
第六章
第七章
第八章
第九章
第十章
第十一章
第十二章
有不正确请提出
第一章
1.1
应该把形参 换成引用
int x--> int &x
1.2
#include
using namespace std;
template //模板形参的类型
int
count (T array,int end,T1 value){
int i =0,count=0;
while(i
1.3
#include
using namespace std;
template
int
fill(T array,int end,T1 value){
int i =0;
while(i
1.4
#include
using namespace std;
template
int
inner_product(T a1, T a2,T2 n){
int i=0;
int value=0;
while( i
1.5
#include
using namespace std;
template
void
iota (T array,int n){
int i=0;
while( i!=n){
array[i] += i;
i++;
}
}
int main(){
int a[]{1,2,3,4,5,6};
iota(a,5);
for(int i=0;i!=5; i++){
cout<
1.6
应该还包括递减的情况
#include
using namespace std;
template
bool
is_sorted(T array,int n){
int i=0;
while(i!=n-1){
if(array[i]>array[i+1])
return false;
i++;
}
return true;
}
int main(){
int a[]{1,4,6,78,666};
cout<< is_sorted(a,5);
return 1;
}
1.7
#include
using namespace std;
template
int
mismatch(T a,T b,int end){
int i(0);
while( i!=end){
if(a[i]!= b[i])
return i;
i++;
}
return -1;
}
int main(){
int a[]{1,2,34,6};
int b[]{1,2,6,888};
cout<< mismatch(a,b,4);
return 0;
}
1.8
具有相同的签名 ,形参的个数和类型相同,与返回值无关
1.9
都调用模板abc, 因为有三个形参
1.10 /1.11
#include
using namespace std;
int
abc(int a,int b,int c){
if(c<1)
throw "有异常!!!"; // 抛出异常
return a+b+c;
}
int main(){
try{
cout<
1.12
#include
using namespace std;
template
bool
make2_array(T **&array,int number_OF_rows,T1 row_Size){
int i=0;
try{
array = new T* [number_OF_rows]; //创建数组指针 类型就是 T **
while(i< number_OF_rows){
array[i] = new T [ row_Size[i] ];
i++;
}
return 1;
}
catch (bad_alloc){
return false;
}
}
int main(){
char **a;
int row_size[]{1,2,4,5,6};
cout<< make2_array(a,3,row_size);
return 1;
}
1.13
#include
using namespace std;
template
T*
change_Length(T *a,int newLength,int oldlength){
if(newLength <=oldlength)
return NULL;
T *newArry = new T [newLength];
for(int i=0; i
1.14
注意: 为数组声明空间时 new 后面的无名数组的 数组名类型必须与 初始化的对象一致
如
int ** a = new int *[];
//int *[] 是个无名数组 ,数组名类型为 int** 与 a一致 可以赋值
#include
using namespace std;
template
T**
changeLength_2D(T ** &array,int row,int col,int oldRow,int oldCol){
T ** newRow= new T * [row];
for(int i=0;i
1.15
[-max_number / 101 ,+max_number/101]
(不确定 dollar *100 + cents <= max number)
1.16
(转换出现了问题)
#include
using namespace std;
enum signType{plus,minus};
class currency{
public:
currency (signType theSign= signType::plus,unsigned long theDollars=0,unsigned int theCents = 0); //构造函数 外部定义 诺省初始值--> 则按此默认给
~currency(){};//析构函数 为空
void setValue(signType,unsigned long,unsigned int ); //原型 定义在class 外部
currency add(const currency&) const; //此const表示 不改变参数的内容
void output() const;
void input(); //(1)
double subtract(double x);//(2)
currency percent(double x);//3
currency mulitiply(double x);
currency div(double x);
private : //只能通过成员函数访问 不能对象私自 访问
signType sign;
unsigned long dollars;
unsigned int cents;
}; //最后也要加分号
currency::currency (signType theSign,unsigned long theDollars,unsigned int theCents){
setValue(theSign,theDollars,theCents);
}
void currency::setValue(signType Sign,unsigned long Dollars,unsigned Cents){ // 如显示初始化对象 ,则调用此 64row
//给调用对象 的成员赋值
if(Cents >99){
throw "Max of Cents";
}
sign = Sign; //没用 . 就代表 访问 调用对象的成员
dollars = Dollars;
cents = Cents;
}
currency currency::add(const currency & x) const{
currency result;
long a1,a2,a3;
a1=dollars*100 + cents; //a1 调用对象的 转换为数字值
if(sign ==signType:: minus)
a1 = -a1;
a2 = x.dollars*100 +x.cents; // a2 代表形参传进来的对象
if(x.sign == signType:: minus)
a2= -a2;
a3= a1+a2;
if(a3<0){
result.sign =signType:: minus;
a3 = -a3;
}
else result.sign = signType::plus;
result.dollars = a3/100;
result.cents = a3-result.dollars*100;
return result;
}
void currency::output() const{
if(sign == signType::minus)
cout<<'-';
cout<< dollars
<< '.'
<< cents <<'\n';
}
void currency::input(){
double temp;
cin>> temp;
temp *=100;
if(temp <0){
sign = signType::minus;
temp = -temp;
}
else sign =signType:: plus;
dollars =(unsigned long)temp/100;
if(temp <0){
cents = (unsigned) (temp-0.01 -dollars*100);
}
else cents = (unsigned)(temp+0.01 - dollars*100);
}
double currency::subtract(double x){
double temp = dollars*100+cents ;
return temp/100 -x;
}
currency currency:: percent(double x){
currency result;
double temp = dollars*100+cents ;
temp =temp* (x/100);
result.dollars = temp /100;
result.cents = temp -dollars*100;
return result;
}
currency currency:: mulitiply(double x){
double temp= (dollars*100+cents )/100;
temp *=x;
currency result;
result.dollars = temp;
if(temp <0){
result. cents = (unsigned) (temp-0.01 -dollars*100);
}
else result. cents = (unsigned)(temp+0.01 - dollars*100);
return result ;
}
currency currency:: div(double x){
double temp= (dollars*100+cents )/100;
temp /=x;
currency result;
result.dollars = temp;
result.cents = (temp-dollars)*100;
return result ;
}
int main(){
currency a(signType::plus,3,22),b(signType ::minus,2,22);
a.input();
a.output();
a.div(10).output();
a.mulitiply(5).output();
//cout<< a.subtract(2.9)<<'\n';
// a.percent(10).output(); //不知道小数为啥不对
return 0;
}
1.17
一样的(只是换成了一个总额 amount 无需dollars 和cents
见 1.18
1.18
#include
using namespace std;
enum signType{plus,minus};
class currency{
public:
currency (signType theSign= signType::plus,unsigned long theDollars=0,unsigned int theCents = 0); //构造函数 外部定义 诺省初始值--> 则按此默认给
~currency(){};//析构函数 为空
void setValue(signType,unsigned long,unsigned int ); //原型 定义在class 外部
currency add(const currency&) const; //此const表示 不改变参数的内容
void output() const;
void input();
double subtract(double x);
currency percent(double x);
currency mulitiply(double x);
currency div(double x);
//--------符号函数
currency operator-(currency &) ; //(1)
currency operator%(currency &);
currency operator*(currency&);
currency operator/(currency&);
friend istream& operator>>(istream&, currency &); // 友元 不是成员函数也能访问
friend ostream& operator<<(ostream&, const currency &) ;
private : //只能通过成员函数访问 不能对象私自 访问
long amount;
}; //最后也要加分号
currency::currency (signType theSign,unsigned long theDollars,unsigned int theCents){
setValue(theSign,theDollars,theCents);
}
void currency::setValue(signType Sign,unsigned long Dollars,unsigned Cents){ // 如显示初始化对象 ,则调用此 64row
//给调用对象 的成员赋值
if(Cents >99){
throw "Max of Cents";
}
amount = Dollars*100+ Cents;
if(Sign== signType::minus)
amount = -amount;
}
currency currency::operator-(currency &x) {
currency result;
result.amount = amount-x.amount;
return result;
}
istream& operator>>(istream &in ,currency &x){ // 友元不是成员函数!! 不用加::
long temp;
in>>temp ;
x.amount = temp*100;
return in;
}
ostream& operator<<(ostream& out,const currency &x) {
long theA=x.amount;
if(theA <0){
out<<'-';
theA = -theA;
}
out<>a>>b;
cout<
1.19
#include
using namespace std;
int factorial(int n){
int result=1;
while(n>0){
result *=n--;
}
return result;
}
int main(){
cout<
1.20
#include
using namespace std;
int count;
int Fibonacci(int n){
int f;
::count++;
if(n==0)
return 0;
else if(n==1||n==2)
f=1;
else
f=Fibonacci(n-1)+Fibonacci(n-2);
return f;
}
int fib(int n){
if(n <=2){
return 1;
}
int f,f1=1,f2=1;
while(n>2){
f=f1+f2;
f2=f1;
f1=f;
n--;
}
return f;
}
int main(){
cout<< Fibonacci(5)<<' '<< ::count <<'\n'<
1.21
#include
using namespace std;
int fun1(int n){
if(n%2 ==0)
return n/2;
else
return fun1(3*n+1);
}
int fun2(int n){
if(n%2 == 0)
return n/2;
else
return (3*n+1)/2;
}
int main(){
cout<< fun1(3)<<'\n'<
1.22
#include
#include
using namespace std;
int Ack(int i,int j){
if(i ==1&& j>=1){
return pow(2,j);
}
else if( i>=2 && j==1)
Ack(i-1,2);
else if(i>=2 && j>=2)
Ack(i-1,(Ack(i,j-1)) ) ;
else return 0;
}
int main(){
cout<
1.23
证明:Fibonacci 数列及其计算方法_Ivan 的专栏-CSDN博客_fibonacci数列
#include
using namespace std;
int Gcd(int x,int y){
if(y == 0)
return x;
return Gcd(y,x%y);
}
int main(){
cout<
1.24
#include
using namespace std;
template
bool
fun(T* array,T value,int end){
for( int i=0;i
1.25
类似二叉树分支
#include
using namespace std;
void Subset(char a[], int n, int len) {
if (n == 0) { // 递归终止条件
for (int i = 0; i < len; i++) cout << a[i];
cout << endl;
delete[] a; // 这里的a 就是temp
return;
}
for (int j = 0; j <= 1; j++) { //每次需要做两种决策
char *temp = new char[len];
for (int i = 0; i < len; i++) temp[i] = a[i]; //用临时数组来覆盖原来数组
if (j == 0) {
temp[n - 1] = '0';
}else {
temp[n - 1] = '1';
}
Subset(temp, n - 1,len);
}
}
int main()
{
char a[3] = { 'a','b','c'};
Subset(a, 3,3);
return 0;
}
1.26
#include
using namespace std;
void
GrayCode(int n){
if(1== n)
cout<<1;
else {
GrayCode(n-1);
cout<
1.27
#include
using namespace std;
template
int
accumulate(T array,int end,int value){
for(int i =0;i
1.28
#include
using namespace std;
template
int
accumulate(T array,int end ,int result,funP p){
for(int i=0; i
1.29
#include
using namespace std;
template
bool
Copy(T a,int n,T b){
for(int i= 0;i
1.30
#include
#include
using namespace std;
int main(){
int a[]={1,2,10};
sort(a,a+3); //无回调函数 默认升序
do{
cout<
1.31
#include
#include
using namespace std;
int main(){
int a[]={2,3,1};
cout << "next is:"<
1.32
#include
#include
#include
using namespace std;
int main(){
int a[]={2,3,1};
while(next_permutation(a,a+3));// 直接到底
do{
cout<
1.33
#include
#include
#include
using namespace std;
int main(){
vector a;
for(int i=0;i<6;i++)
{
int temp;
cin>>temp;
a.push_back(temp);
}
cout<
1.34
#include
#include
using namespace std;
int main(){
int a[10];
fill(a,a+10,6); //参数应是个迭代器类型(指针)
for(int i=0;i<10;i++){
cout<< a[i]<<' ';
}
cout<< endl;
return 0;
}
1.35
#include // inner_product 在此头文件
#include
using namespace std;
int main(){
int a[]={1,2,3,4,5,6};//内积?? 自己跟自己
cout<
1.36
#include
#include
using namespace std;
int main(){
int a[8];
iota(a,a+8,6); //初始值 递增 !
for(int i=0;i<8;i++){
cout<
1.37
#include
#include
using namespace std;
int main(){
int a[]={99,8,6,4,2};
cout<
1.38
pair 没学到 不太会 matching返回的是什么?
#include
#include
#include
using namespace std;
int main(){
int a[]={1,2,3,4,5,6};
int b[]={1,2,3,4,5,999};
pair result;
result = mismatch(a,a+6,b); //返回不相等的两个元素??
cout<< *result.first<<' '<<*result.second;
return 0;
}
1.39
#include
using namespace std;
template
int
STL_count(T start, T end,int value){
int result =0;
for( int i=0; start+i
1.40
#include
using namespace std;
template
void
STL_fill(T *start,T* end,T value){
for(int i =0; start+i
1.41
#include
using namespace std;
template
T
inner(T *start,T *end,T* start1,T *end1){
int i=0;
int result =0;
while( start+i
1.42
#include
using namespace std;
template
void
ioat(T *start,T *end,T value){
for(int i=0;start+i
1.43
#include
using namespace std;
template
bool
is_sorted(T start,T end){
int i=0;
while(start+istart[i+1])
return false;
i++;
}
return true;
}
int main(){
int a[]{1,2,5,8,999};
cout<< is_sorted(a,a+5);
return 0;
}
1.44
#include//错的 待改
using namespace std;
template
// 该返回什么????
mismatch(T strart,T end,T strart1){
int i=0;
while(strart+i result;
result = mismatch(a,a+6,b); //返回不相等的两个元素??
cout<< *result.first<<' '<<*result.second;
return 0;
}
1.45
因为每一条语句 本身就是从句(无再细分布尔式)
1.46
{a,3}
a={2,4,1}
1.47
两条 : 1 2 3? 4
1.48
n条执行路径(当n固定时 步骤也是固定的 ,递归)
执行的语句条数为 2N+2
第一章总结:
c++部分 :
函数传参:
a 传值
b 传引用 (与指针一样都要临时变量空间
c 传指针
模板参数:
template
函数体
异常 :
throw
try{}
catch()
动态分配:
new
delete
自定义类class
构造函数
析构函数
方法
符号重载
友元(不算成员函数
递归
归纳
-->基础表达式
STL (重点
自带的算法
测试与调试
重点:测试的目的是为了暴露程序的错误,而不是证明是否正确
测试集 :
黑盒 : 分结果种类
白盒:
语句覆盖:每条语句至少执行一次
分支覆盖 :程序的每个条件都分别去true 和 false
从句覆盖: 最小子单元的判断-->从句
执行路径覆盖: 有可能走的路径 都要经过 ?
边界测试:如数组边界时
调试:
逻辑推理
必要时重新设计
增量测试
第二章(时间/空间复杂度)
2.1
有更多的空间留作他用
模拟计算程序最大的规模
2.2
省钱
有更大市场
2.3
都有可能
2.4
硬件/编译器/优化/使用的语言
2.5
24 4k 8k 2w 24 324
2.6
12* MAX[n-1,1]
2.7
非递归n! S= 0
1-29 为8N
时间
2.8
v=v*2+C(n-i)
2.9
r= [2,1,5,4,8]
2.10-2.17
略 自己画图很简单
2.18
2n
2.19
n-1次
2.20
a={5,4,3,2,1}.
只要使a[i] != r[i] 即可
2.21
(row-1)的平方
2.22
就是swap的频率
row*(row-1)/2
2.23
n的三次方
2.24
n*p*m
2.25
2* {(m-k+1)k[1,m]的连加}
2.26
2*(n-1).
n-1
下一个性能更好
2.27
n+1
2n+1
2.29
#include
using namespace std;
void
fun(int *x,int n){
int count =0;
count++ ;
for(int i=0;i
2.30
(1)- (8) 略
(9 :
最坏: 2n+4
(10:
最好 :n
最坏: 3n+n*(n-1)/2 -2
(11:
最好 :3n+1
最坏: 3n(n-1)/2 +n+1
(12:
调用函数步数都是一样的 ,关键看被调用里面的函数步数
最好: n+n-1+ (n+3) n=[1,n-1]的累加
最坏: n+n-1+ (2n+3) n=[1,n-1]的累加
(13:
最坏:
n+2(n-1)+(2+n)(n-1)-1+(n-1)
(14:
(2n-1) n=【2,n】 的累加
(15:
(4n-1)n=【2,n】 的累加
1.31
略
1.32
1):
(3n+3)/2
2):
(2n+6)/2
3):
(3n+8)/2
1.33
条件一样时可以交换??
1.34
2-12: 3/2 *n的平方-1/n-1
2-15: n方+5n-7
2-13: 2*n方+n-3
最坏应该冒泡比较好?
1.35
不一定吧,因为内存S(q)可能跟特征值没关系
1.36
技巧:算出n不是非基础部分的次数 ,最后一次就是基础部分
1) 【n,1】 共n次非基础部分 2*n + 基础部分 2
--> 总 2n+2
2) (n-1)/2 +1
3) 2n n[1,n]的累加
4) 2的n-1次方 +1
5) 3的n-1次方+1
第二章总结:
分为 空间复杂度和时间复杂度
空间:(变量,常量,返回地址等)
C+S(n) : 其中s(n) 是可变的 -->实列特征
与多种可能有关
时间:
编译时间+ 运行时间
因为编译时间不受实列特征影响,所以我们注重运行时间 !
运行时间:
a 找出关键操作(加法,乘法次数
b 确定总步数 (包括调用,递归等)
B步数:
分为最好情况和最坏情况
平均 == (最坏+最好)/2 因为每一个概率都相等
步数方法:
1 变量法 设置全局变量写进代码 来++
2 剖析法:
确定每一条语句的步数 *频率
小技巧::
for循环时 :
for本身次数 : 如果有边界 [ a,b ) 为b-a+1
如果没有边界 [a,b] 为a-b+2
进入for的次数: 为for本身次数-1
递归时:
如果非基础部分易看 , 可以分析出进行非基础部分递归的次数
然后加以条件 再加基础部分
补充: 新算法排序(名次排序) new rank数组 --> 记录下标元素比原数组小的数 +本数左边与其相等的数 。 rank数组的值 就应该是对应的位置 a[r[0]]= a[0]
第三章
3.1
统一 p(n)/q(n) ,因为最高次不一样 就会趋于0
证明完成
3.2
O(). 取最大次项 ,再将系数化为1即可
3.3
3n+7<3n+n=4n 当c= 8 时 使得g(n) 大于f(n)
所以f(n) = O(n).
其他一样证
3.4
一样 ,取最大项
3.5
g(n) / f(n) 看是否趋于 0即可
或推导 >= 都 c n0
3.6
最大次项
3.7
Ω(n) <= f(n) <= O(n)
直接找
3.8
因为多元 :
小技巧: 如果一个式子是因式,则直接消除
如 3mn^2+7m^2n+4mn+8m+2n+16
-->后四项都是前面的因式
--> =O(mn^2+m^2)
渐进数学: 难死了 数学还是重要
3.9
找 n0 c 推出
3.10
用两式子相除,得到大于 >=(<=) C
注意:Θ 要两边除 得到两边边界。
3.11
用定理或定义 推出正确结果
3.12
还真不会 应该是:
大于等于 (每次少最小一项 ) -->
最后>= an^m
3.13
反证? 存在 m
3.14
反过来不知道怎么证, 后条件只能证明 g(n) 是f(n) 的上界呀 ,
怎么证明f(n)一定渐进小于g(n) ,不包括等于的情况
3.15
纯数学求和 ,建议百度
E4,5
这个通项公式是一个非常特别的
公式为
1^k+2^k+...+n^k=((n+1+p)^(k+1)-p^(k+1))/(k+1)
我们先要求一个数字p,p满足以下规则
(1+p)^(k+1)-p^(k+1)=0这个里面首先要展开,展开后对于p,p^2 p^3等,我们要当成一个整体对待,比
E6
最大次
E7
放缩法
E8
lim[1/(n+1)+1/(n+2)+......+1/(n+n)]=lim(1/n)[1/(1+1/n)+1/(1+2/n)+......+1/(1+n/n)]=定积分(上限1,下限0)[1/(1+x)]dx=ln(1+x)(上限1,下限0)=ln(1+1)-ln(1+0)=ln2.
3.16
只可意会不可言传
3.17
还真不会
不过应该往松条件取
3.18
1) Θ (n)
Θ (n)
Θ (n)
Θ (n^2)
Θ (n^3)
Θ (m*p*n)
Θ (n)
Θ (n)
Θ (n)
10) Θ (n^2)
Θ (n*n!)
Θ (n^2)
Ω(n). O(n^2)
Θ (n^2)
Ω(n). O(n^2)
Θ (n^2)
17). Ω(n). O(n^2)
3.19
1) n>100
2) n>2
3) n<10
4) 带数测试 n[2^13,2^14] 中间取到相等
3.20
略 ,乘上倍数就行了
3.21
n不同 t(n) 的规模也不同。
以n== 100 为例子 n的最高次每增加一次 效率是1/100 倍 然后根据x的增加 比较一下即可
第三章总结:
渐进记忆法:
1 O(n) 最小上界
2 Ω(n) 最大下届
3 Θ(n) f的上界和下界都是同一个函数的情况 ,C可以不同
4 o(n) 小于上界, f(n) 一定渐进小于 cg(n),不包括等于
1:
定义: 存在 C,n0 ,使得 n>n0 时 f(n) <= C*g(n)
a: g(n) 的类型就是我们通常算时间复杂度的函数类型(如对数阶
b: 可以通过找C ,g(n) 来确定O(n).
c: 通常找最小上界,才有实际意义
定理:
f(n) = O(最高次的项)
f(n)/g(n) <= C 当且仅当 f(n) = O(g(n) )
2.
定义: 存在 C,n0 ,使得 n>n0 时 f(n) >= C*g(n)
a: 这就是下界 ,f(n) 一定渐进大于或等于 cg(n)
b:通常最大下届取
定理:
f(n) = O(最高次的项)
f(n)/g(n) >= C 当且仅当 f(n) =Ω (g(n) )
3.
定义 : 存在 c1,c2,n0 ,使得n>n0时 c1*g(n) <= f(n) <= c2*g(n)
定理:
f(n) = O(最高次的项)
假设f(n) 和g(n) 都有极限 f(n)/g(n) 和 g(n)/f(n) 存在 , 当且仅当
f(n)/g(n)<=c 以及 g(n)/f(n)<= c 存在
4.
严格小于c*g(n)
另外:也可以推广到多元函数 :
任意一元趋于无穷 ,两函数比例为无穷 且 另一元趋于无穷,两函数比例为0
第四章
测试模板::
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义
int main(){
int a[MAX_];
int step =10;
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
for(int n= 0;n<= MAX_;n+= step){
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
do{
numberRepetitions++;
//初始化数组for
//...调用函数
}while (clock()- startTime <1000);
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
cout<< n <<'\t'<< numberRepetitions <<'\t'<< elapsedMillis/numberRepetitions<
但是n到不了1000 会溢出 不知道怎么办
4.1
因为没有除以 clocksPerMillis ,代表一毫秒
4.2
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template
void insertionSort(T *a,int n){
for(int i=1;i=0 && t
可以看到如果是最好情况,是线性增长的 说明O(n)![数据结构 算法与应用(c++ 描述) 自练答案_第1张图片](http://img.e-com-net.com/image/info8/2fc62ee67519425592cffcfc5304e5c7.jpg)
最坏:不是线性的 n不够大导致不是很明显 O(n^2)
所以2-15的程序好一点 ,最好情况是n 而2-14 都是n^2
4.3
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template
void
bubbleSort1(T *a,int n){
for(int i=n;i>1;i--){
for(int j=0;ja[j+1])
swap(a[j],a[j+1]);
}
}
template
void
bubbleSort2(T *a,int n){
bool swapped = true;
for(int i=n;i>1 &&swapped ;i--){
swapped = false;
for(int j=0;ja[j+1]){
swap(a[j],a[j+1]);
swapped = true;
}
}
}
int main(){
int a[MAX_];
int step =10;
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
for(int n= 0;n<= MAX_;n+= step){
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
do{
numberRepetitions++;
//初始化数组for
for(int i=0;i
可以看到结果
![数据结构 算法与应用(c++ 描述) 自练答案_第3张图片](http://img.e-com-net.com/image/info8/bbd2edb7500d485ea6026d7a12704276.jpg)
说明最坏情况下(逆序,每两个比较都要交换) 性能基本一致
4.4/5
略 思路基本一致
4.6
正确形式应该如4.7
#include
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template
void insertionSort(T *a,int n){
for(int i=1;i=0 && t
固定排列数为1k 结果:
感觉平均时间是O(n)
4.7
#include
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template
void
bubbleSort1(T *a,int n){
for(int i=n;i>1;i--){
for(int j=0;ja[j+1])
swap(a[j],a[j+1]);
}
}
template
void
bubbleSort2(T *a,int n){
bool swapped = true;
for(int i=n;i>1 &&swapped ;i--){
swapped = false;
for(int j=0;ja[j+1]){
swap(a[j],a[j+1]);
swapped = true;
}
}
}
int main(){
int a[MAX_];
int step =10;
time_t t;
srand((unsigned)time(&t));
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
int count =0;
while(count<20){
for(int i=0;i
结果:
![数据结构 算法与应用(c++ 描述) 自练答案_第5张图片](http://img.e-com-net.com/image/info8/07b9f279833b4f2a8ccb5d0297d7c369.jpg)
明显终止冒泡平均优于普通的
4.8/9
略 思路一样
4.10
#include
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template
int
sequntialSearch(int *a,int n,const T& x){
int i;
for(i=0;i
int
binarySearch(T *a,int n,const T&x){
int left =0;
int right=n-1;
while(left <=right){
int mid= (left+right)/2;
if(x== a[mid]) return mid;
if( x>a[mid]) left=mid+1;
else right=mid-1;
}
return -1;
}
int main(){
int a[MAX_];
for(int i=0;i
结果:
![数据结构 算法与应用(c++ 描述) 自练答案_第6张图片](http://img.e-com-net.com/image/info8/40b758e626074b3ba1edbc312a4d9e9e.jpg)
折半查找明显好于 顺序查找!
4.11
最坏情况:查找元素为最后一个
#include
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template
int
sequntialSearch(int *a,int n,const T& x){
int i;
for(i=0;i
int
binarySearch(T *a,int n,const T&x){
int left =0;
int right=n-1;
while(left <=right){
int mid= (left+right)/2;
if(x== a[mid]) return mid;
if( x>a[mid]) left=mid+1;
else right=mid-1;
}
return -1;
}
int main(){
int a[MAX_];
for(int i=0;i
结果:
![](http://img.e-com-net.com/image/info8/99cff3dad2c14457aa0f03eb746b68da.jpg)
高下立判
4.12
略
4.13
#include
#include
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义
template
void insertionSort(T *a,int n){
for(int i=1;i=0 && t
最好结果:
![数据结构 算法与应用(c++ 描述) 自练答案_第7张图片](http://img.e-com-net.com/image/info8/a430fb2af8184c438a7148281d5d7cb6.jpg)
最坏结果:
感觉两个运行时间差不多,性能差不多?
4.14/15
略
4.16
略
4.17
#include
#include
using namespace std;
void
TransposeMatri(int **array,int n){
for(int i=0;ii)//主副三角
swap(array[i][j],array[j][i]);
}
}
void
matrixMultiplication(int **a,int **b,int **c,int n){
TransposeMatri(b,n);//先转置
for(int i=0;i
4.18
(1条消息) C++性能优化系列——矩阵转置(二)循环分块优化缓存访问_yan31415的博客-CSDN博客
自己写的有误,最远处的对角并没有互换,思路错了
#include
#include
using namespace std;
void TransposeMatri(int **array, int n) { //全部转置
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++) {
if(j > i) //主副三角
//swap(array[i][j], array[j][i]);
swap((*(int (*)[n][n])(array))[i][j], (*(int (*)[n][n])(array))[j][i]);
}
}
void Block_transpose(int **array, int n) { //分块转置
/*
int k = 2;
for(int i = 0; i < n; i += k)
for(int j = 0; j < n; j += k)
TransposeMatri((int **)((int *)array + i * n + j), k);
*/
int k = 2;
for(int i = 0; i < n; i += k)
for(int j = 0; j < n; j += k) {
int a[k][k];
for(int y = 0; y < k; ++y) {
for(int x = 0; x < k; ++x) {
a[y][x] = (*(int (*)[n][n])array)[i + y][j + x];
}
}
//TransposeMatri((int **)((int *)array + i * n + j), k);
TransposeMatri((int **)a, k);
for(int y = 0; y < k; ++y) {
for(int x = 0; x < k; ++x) {
(*(int (*)[n][n])array)[i + y][j + x] = a[y][x];
}
}
}
}
int main() {
/*
int **a = new int *[4];
for(int i = 0; i < 4; i++)
a[i] = new int[4];
*/
int a[4][4];
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++) {
a[i][j] = i * 4 + j;
}
}
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++)
cout << a[i][j] << ' ';
cout << endl;
}
//Block_transpose(a, 4);
Block_transpose((int **)a, 4);
cout << "---------------------" << endl;
/*
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
cout << a[i][j] << ' ';
cout << endl;
*/
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++)
cout << a[i][j] << ' ';
cout << endl;
}
/*
// 释放一定要写,不写释放的代码在一些环境下会报错的
for(int i = 0; i < 4; i++)
delete[] a[i];
delete[] a;
*/
return 0;
}
第四章总结
性能测试:
可以通过程序来测量运行所用的时间 clock()
1.可以设置n的数量
2.设置数组的好坏
来模拟最好(坏)的情况 时间随n的增长;一般数字大时才明显O()
缓存(访问模式)对性能(时间)的影响
分为 :
寄存器,L1,L2,主存 等 ,每一个传输周期都会增长很多 ,如果缓存为命中,到下一 级 去找,花费更多时间
如数组的行是线性存放的,很有可能在一个缓存等级中,而列可能相隔很远,在下一个缓存等 级中,将花费更多时间 (矩阵的相乘,ijk->ikj 书p89);
第五章
注意::
copy(start+index,end,start) --> 访问的就是 start[index] 这个元素
第一个参数是头指针,第二个参数是尾后指针 ,第三个是目的地头指针
arraylist(总)
#include
#include
#include
using namespace std;
template // 抽象类 相当于提供接口? 派生类定义这些函数?
class linearList{
//都是纯虚函数
public:
virtual ~linearList(){};
virtual bool empty() const =0;
// virtual int size()const =0;
// virtual T& get(int theIndex) const =0;
// virtual int indexOF(const T& theElement) const = 0;
// virtual void erase(int index) =0;
// virtual void insert(int theIndex,const T& theElment) = 0;
virtual void output(ostream &out) const =0;
};
template
class arrayList:public linearList //从抽象类派生出的具体类(必须全部实现基类的函数才算)
{
public:
arrayList(int initCapacity =10); //构造函数
arrayList(const arrayList&); //赋值函数
arrayList(const arrayList&,const int ReInit = 0);
~arrayList(){
delete [] element;
}
//ADT 抽象类本身带的
bool empty() const {return listSize == 0;}//1
int size() const {return listSize ;} //1
int lenth()const{ return arrayLength;}//1
T& get(int theIndex) const;//0
int indexOF(const T& theElment) const;
void erase(int theIndex);
void insert(int theIndex,const T& theElement);
void output(ostream & out) const;
void setSize(int newSize);
void leftShift(int i);//左移i
T substitution(int index ,T value );//置换index
void merge(arrayList& ,arrayList&);
void split(arrayList& ,arrayList&);
void ChangeArray();
void SetChange(int ALength);
void trimToSize();//5.5
void swap(arrayList& );
void reverse();//翻转线性表
void meld(arrayList& ,arrayList&);//合并新链表到调用对象
void clear();//使线性表为空
void removeRange(int start,int end);//删除索引范围内的所有元素
int lastInexOf(T TheElement);//返回出现的最后索引,若无返回-1
void circularShift(int i);//循环左移
//派生类还可以自己添加方法
void half();//隔一个删一个
void push_back(T theElement);
void pop_back();
int capacity() const{return arrayLength; }
T& operator[](unsigned index); //返回& 就能作为左值
bool operator==(const arrayList& x)const ;
bool operator!=(const arrayList& x) const{ bool result = (*this)==x; return !result; }
bool operator<(const arrayList& x) const;
// 成员也能是类 --》 迭代器
class iterator;
iterator begin(){return iterator(element);}
iterator end(){return iterator(element+listSize);}
friend ostream& operator<<(ostream &out,const arrayList& x){ //把友元函数体放到类声明内部,使其跟着类的实例化一同实例化:
x.output(out);
return out;
}
protected://保护成员 不是私有成员 ©️函数能直接访问?
bool checkIndex(int theIndex) const;
T *element;
int arrayLength;
int listSize;
};
template
class iterator{
public:
typedef bidirectional_iterator_tag iterator_category;
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef T& reference;
iterator(T* theposition = 0){ position = theposition;}
T& operator*() const {return *position;}
T* operator->() const{return &*position;}
iterator& operator++(){++position ;return *this;}
iterator operator++(int){iterator old= *this; ++position; return old;}
iterator& operator--(){--position;return *this;}
iterator operator--(int){iterator old = *this; --position;return old;}
iterator operator+=(int i){position+= i;return *this;}
iterator operator-=(int i){position-= i;return *this;}
bool operator!=(const iterator right) const{ return position!= right.position;}
bool operator==(const iterator right) const{ return position== right.position;}
protected:
T* position;
} ;
template
arrayList::arrayList(int initCapacity ){
if( initCapacity<1){
cout<< "must > 0";
exit(1);
}
arrayLength = initCapacity;
listSize =0;
element = new T[initCapacity];
}
template
arrayList::arrayList(const arrayList& theList){
arrayLength = theList.arrayLength;
listSize = theList.listSize;
element = new T[arrayLength];
copy(theList.element,theList.element+arrayLength,element);//前两个是范围 最后一个参数是目的地
}
template
arrayList:: arrayList(const arrayList& x,const int ReInit){
//x 满了 就构造一个 新指定数组?
T *temp;
if(x.listSize == x.arrayLength){
if(ReInit == 0){//没指定 默认翻倍
arrayLength = x.arrayLength*2;
temp = new T[arrayLength];
listSize = x.listSize;
copy(x.element,x.element+x.listSize,element);
delete [] x.element;
}
else {
arrayLength = ReInit;
temp = new T[arrayLength];
listSize = x.listSize;
copy(x.element,x.element+x.listSize,element);
delete [] x.element;
}
}
}
template
bool
arrayList::checkIndex(int theIndex) const{
//确定索引是否合法
if(theIndex<0 || theIndex>= arrayLength){
cout<< "Cross the border"<
void
arrayList::output(ostream & out) const{
copy(element,element+listSize,ostream_iterator(cout," "));//0
}
template
void
arrayList:: insert(int theIndex,const T& theElement){
if ( checkIndex(theIndex)==0 ) {
exit(1);
}
if(listSize == arrayLength){
ChangeArray();
}
copy_backward(element+ theIndex,element+ listSize,element+ listSize+1) ;// 尾部对尾部
element[theIndex]= theElement;
listSize++;
}
template
void
arrayList::setSize(int newSize){
while(newSize
void
arrayList::erase(int theIndex){
checkIndex(theIndex);
copy(element+theIndex+1,element+listSize+1,element+theIndex);//就是当前元素就行了 a【index】
element[--listSize].~T();//析构函数
if(listSize<=arrayLength/4){
SetChange(arrayLength/2>10?arrayLength/2:10);
}
}
template
void
arrayList::trimToSize(){
T *temp = new T [listSize];
copy(element,element+listSize-1,temp);//复杂度 O(listsize)
delete [] element;
arrayLength = listSize;
element = temp;
}
template
T&
arrayList::operator[](unsigned index){ //返回& 就能作为左值
checkIndex(index);
return element[index];
}
template
bool
arrayList:: operator==(const arrayList& x)const {
if(listSize == x.listSize){
for(int i=0;i
bool
arrayList:: operator<(const arrayList& x) const{
for(int i=0;i x.element[i])return false;
}
return false;
}
template
void
arrayList::ChangeArray(){
T *temp = new T [arrayLength*2];
copy(element,element+listSize-1,temp);//复杂度 O(listsize)
delete [] element;
arrayLength = listSize*2;
element = temp;
}
template
void
arrayList:: SetChange(int Asize){
T *temp = new T [Asize];
copy(element,element+listSize+1,temp);//复杂度 O(listsize)
delete [] element;
arrayLength = Asize;
element = temp;
}
template
void
arrayList::push_back(T theElement){
if(listSize == arrayLength)
ChangeArray();//默认翻两倍
//第三个参数
copy_backward(element+arrayLength-listSize,element+arrayLength,element+arrayLength-1);//第二个尾部迭代器
element[arrayLength-1]=theElement;
listSize++;
}
template
void
arrayList::pop_back(){
if(empty()){
cout<<"error"<
void
arrayList::swap(arrayList& x){
int i =0;
arrayLength>x.arrayLength? x.setSize(arrayLength):setSize(x.arrayLength); //同长
while (i
T
arrayList::substitution(int Index,T theElement){
T temp = element[Index];
element[Index]= theElement;
return temp;
}
template
void
arrayList::clear(){
listSize =0;
}
template
void
arrayList::removeRange(int startIndex,int endIndex){
checkIndex(endIndex);
checkIndex(startIndex);
copy(element+endIndex+1,element+listSize,element+startIndex);
listSize -= endIndex-startIndex+1;
}
template
int
arrayList::lastInexOf(T value){
int index=-1;
for( int i=0;i
void
arrayList::reverse(){
if(empty() )
exit(1);
int end = listSize-1;
int start = 0;
while(start
void
reverse( arrayList & x){
x.reverse();
}
template
void
arrayList::leftShift(int i){
copy(element+i,element+listSize,element);
listSize -= i;
}
template
void
arrayList::circularShift(int i){
T *temp= new T[i];
copy(element,element+i,temp);
copy(element+i,element+listSize,element);//1
copy(temp,temp+i,element+listSize-i);
delete [] temp;
}
template
void
arrayList::half(){
bool flag =false;
for(int i=0; i
void
arrayList::meld(arrayList& a,arrayList& b){
if(this->arrayLengthSetChange(a.listSize+b.listSize); //不够扩充调用数组
int i=0, k=0;
for(;i
void
arrayList::merge(arrayList &a, arrayList &b){
if(this->arrayLengthSetChange(a.listSize+b.listSize); //不够扩充调用数组
int i=0,j=0,k=0;
while(a.listSize&& j
void
arrayList::split(arrayList &a, arrayList &b){
int i=0,j=0;
for(int k=0;ksize();k++){
if(k%2 == 0)
a.element[i++]= element[k];
else b.element[j++]= element[k];
}
a.listSize = i;
b.listSize = j;
}
int main(){
arrayList a(10),b(10),c(10);
//
return 0;
}
5.1
看描述说明就行
对应的成员函数是什么功能
5.2
size ==2 ;
5.3
前面好像写过,略
5.4
没明白题目意思
template
arrayList:: arrayList(const arrayList& x,const int ReInit){
//x 满了 就构造一个 新指定数组?
T *temp;
if(x.listSize == x.arrayLength){
if(ReInit == 0){//没指定 默认翻倍
arrayLength = x.arrayLength*2;
temp = new T[arrayLength];
listSize = x.listSize;
copy(x.element,x.element+x.listSize,element);
delete [] x.element;
}
else {
arrayLength = ReInit;
temp = new T[arrayLength];
listSize = x.listSize;
copy(x.element,x.element+x.listSize,element);
delete [] x.element;
}
}
}
5.5
template
void
arrayList::trimToSize(){
T *temp = new T [listSize];
copy(element,element+listSize-1,temp);//复杂度 O(listsize)
delete [] element;
arrayLength = listSize;
element = temp;
}
5.6
O(newSize)
要调用析构函数吗??
template
void
arrayList::setSize(int newSize){
while(newSize
5.7
T& operator[](unsigned index){ //返回& 就能作为左值
checkIndex(index);
return element[index];
}
5.8
bool operator==(const arrayList& x)const {
if(listSize == x.listSize){
for(int i=0;i
5.9
bool operator!=(const arrayList& x) const{
bool result = (*this)==x;
return !result;
}
5.10
template
bool
arrayList:: operator<(const arrayList& x) const{
for(int i=0;i x.element[i])return false;
}
return false;
}
5.11.12
template
void
arrayList::push_back(T theElement){
if(listSize == arrayLength)
ChangeArray();//默认翻两倍
//第三个参数
copy_backward(element+arrayLength-listSize,element+arrayLength,element+arrayLength-1);//第二个尾部迭代器
element[arrayLength-1]=theElement;
listSize++;
}
template
void
arrayList::pop_back(){
if(empty()){
cout<<"error"<
5.13
template
void
arrayList::swap(arrayList& x){
int i =0;
arrayLength>x.arrayLength? x.setSize(arrayLength):setSize(x.arrayLength); //同长
while (i
void
arrayList:: SetChange(int Asize){
T *temp = new T [Asize];
copy(element,element+listSize+1,temp);
delete [] element;
arrayLength = Asize;
element = temp;
}
O(arrayLength) 因为不知道是怎么储存的,只能复制整个数组
5.14
就是上一题的 SetChange()
5.15
template
T
arrayList::substitution(int Index,T theElement){
T temp = element[Index];
element[Index]= theElement;
return temp;
}
5.16
template
void
arrayList::clear(){
listSize =0;
}
O(1) 不需要删除
5.17
template
void
arrayList::removeRange(int startIndex,int endIndex){
checkIndex(endIndex);
checkIndex(startIndex);
copy(element+endIndex+1,element+listSize,element+startIndex);
listSize -= endIndex-startIndex+1;
}
O(end-start);
5.18
template
int
arrayList::lastInexOf(T value){
int index=-1;
for( int i=0;i
O(listSize)
5.19
5.20
template
void
arrayList::erase(int theIndex){
checkIndex(theIndex);
copy(element+theIndex+1,element+listSize+1,element+theIndex);//就是当前元素就行了 a【index】
element[--listSize].~T();//析构函数
if(listSize<=arrayLength/4){
SetChange(arrayLength/2>10?arrayLength/2:10);
}
}
删除:减半数组可能 增加:可能倍增数组
道理应该一样的
5.21
略,不好解释
5.22
template
void
arrayList::reverse(){
int end = listSize-1;
int start = 0;
while(start
2) O(listSize) 是listSize的一半
3) {空集} {1} {1,2,3}
4)
template
void
reverse( arrayList & x){
x.reverse();
}
5) 一样的 O(listSize)
6) 应该是对象直接调用性能好 而不是多一层函数调用
5.23
template
void
arrayList::leftShift(int i){
copy(element+i,element+listSize,element);
listSize -= i;
}
O(n)
5.24
template
void
arrayList::circularShift(int i){
T *temp= new T[i];
copy(element,element+i,temp);
copy(element+i,element+listSize,element);//1
copy(temp,temp+i,element+listSize-i);
delete [] temp;
}
创建一个新数组,暂时保存 然后移到末尾
O(n)
5.25
template
void
arrayList::half(){
bool flag =false;
for(int i=0; i
我这应该为O(n^2) ,原地
应该创建一个新数组复制过去
5.26
调用erase,略
5.27
c++ 不太会 到时候再补
iterator& operator+=(int i){position+= i;return *this;}
iterator& operator-=(int i){position-= i;return *this;}
还有+ /- 等
STL 之随机访问迭代器_ Yours风之恋 ~~~~~-CSDN博客_随机访问迭代器
5.28
template
void
arrayList::meld(arrayList& a,arrayList& b){
if(this->arrayLengthSetChange(a.listSize+b.listSize); //不够扩充调用数组
int i=0, k=0;
for(;i
很容易证明 O(a.listSize+b.listSize)
5.29
template
void
arrayList::merge(arrayList &a, arrayList &b){
if(this->arrayLengthSetChange(a.listSize+b.listSize); //不够扩充调用数组
int i=0,j=0,k=0;
while(a.listSize&& j a(10),b(10),c(10);
cout<
复杂度O(n)
5.30
template
void
arrayList::split(arrayList &a, arrayList &b){
int i=0,j=0;
for(int k=0;ksize();k++){
if(k%2 == 0)
a.element[i++]= element[k];
else b.element[j++]= element[k];
}
a.listSize = i;
b.listSize = j;
}
O(size)
5.31
#include
#include
using namespace std;
template
class circularArrayList{
public:
circularArrayList(int init =10);
~circularArrayList(){ delete []element;}
void erase(int index);
void insert(T ElementValue);
T& operator[](unsigned index); //返回& 就能作为左值
friend ostream& operator<<(ostream &out,const circularArrayList& x){ //把友元函数体放到类声明内部,使其跟着类的实例化一同实例化:
x.output(out);
return out;
}
void output(ostream & out) const{
copy(element,element+arraylist,ostream_iterator(cout," "));
}
int lenth()const{ return arrayLength;}
int getEND()const {return end;}
protected://保护成员 不是私有成员 函数能直接访问?
T *element;
int arrayLength;
int start;
int end;
int arraylist;
};
template
circularArrayList::circularArrayList(int init){
element = new T[init];
start = init-1;//下标 向右端储存
end=init-2;
arrayLength = init;
arraylist =0;
}
template
void
circularArrayList::erase(int index){
if(index>=start && index
void
circularArrayList::insert(T value){
if(arraylist == arrayLength){
;//倍增
}
end=(end+1)%arrayLength;
element[end]=value;
arraylist++;
}
template
T&
circularArrayList::operator[](unsigned index){ //返回& 就能作为左值
return element[index];
}
int main(){
circularArrayList a(10);
for(int i=0; i<10;i++)
a.insert(i+1);
for(int i = 0;i
5.32
应该跟书上差不多 只不过下标循环
5.32-5.36
略,思路跟差不多
只是 下标的表达不同
vectorList
5.37
template
void
verctorList::half(){
bool flag =false;
for(int i=0;i
5.37 , 38
template
void
verctorList::merge(vector& a,vector & b){
if(element->sizeresize(a.size()+b.size());
int i=0,j=0,k=0;
while( i
e. vector 对象下标运算符可以访问已存在的元素,而不能用于添加元素
应该用insert
5.40
template
void
verctorList::split(vector& a,vector & b){
int i=0,j=0;
for(int k=0;ksize();k++){
if(k%2 == 0)
a[i++]= (*element)[k];
else b[j++]= (*element)[k];
}
}
自行测试。。
5.41 -43
应该还有错误
#include
using namespace std;
#define MaxSize 100
#define Type int
#define MAXList 20
Type Array[MaxSize];
Type *lastA[MAXList];//M个表 指针数组
Type *frontA[MAXList];
int count;
bool Move_forward(int ListNum);//移动到上一个尾部
bool Move_backward(int ListNum);
template
class MultipleTable{
public:
MultipleTable(int start=0);
void insert(T value);
void erase(int index);
T* front;
T* last;
int ListNum;
};
template
MultipleTable::MultipleTable(int start){
if( start>=MaxSize || (count>0 && start <= *frontA[count-1] ) ) {//如果不是第一个表 且 front【i】 < last[i-1]
cout<<"error "<
void
MultipleTable::insert(T value){
if( (ListNum==count-1 && lastA[ListNum]< Array+MaxSize) || last[ListNum]0 && front[ListNum]>last[ListNum-1]){//查看前面有无空间
Move_forward(ListNum);
*++lastA[ListNum]=value;
}
else { // 前后都是满的
int index = 1;
bool flag = false;
while(index <=ListNum)
if(Move_forward(index++) ) //循环移0-i表
flag = true;
if(flag) //至少一移动了一个
*++lastA[ListNum]=value;
else{
index=count-1;
flag =false;
while(index > ListNum)//i+1 到M 向后移
if(Move_backward(index--))
flag =true;
if(flag)
*++lastA[ListNum]=value;
else cout<<"fluat!!"<
void
MultipleTable::erase(int index){
if(index<1 )
cout<<"-1"< a(0),b(40);
a.insert(666);
cout<< *lastA[a.ListNum]<
5.44
略 ,自行实现STL函数,大部分用指针
然后用第四章的方法测速
第五章总结
抽象数据类型:
不依赖语言而描述,ADT ,类提供接口
c++: 抽象类的派生类(抽象类的函数全部具体重写的派生类才算实体类,才能实例化)
本章主要讲解了 关于线性表 -- 数组描述
创建一个类包含对数组线性的许多方法 ,但会造成空间浪费 ;
一个数组实现多重表(省空间,但是操作复杂)
基于数组的类 vector ,也有许多方法,也支持迭代器
自写迭代器类:还不太懂 继续学习c++(重载 指针操作?)
第六章
chain总代码:(未完待续)
#include
#include
#include
using namespace std;
class arrayList;
class illegaParameterValue{
public:
illegaParameterValue():
message("Illegal value"){}
illegaParameterValue(char * theMessage){
message = theMessage;
}
void outputMessage(){ cout<< message< // 抽象类 相当于提供接口? 派生类定义这些函数?
class linearList{
// 都是纯虚函数
public:
virtual ~linearList(){};
virtual bool empty() const =0;
virtual int size()const =0;
virtual T& get(int theIndex) const =0;
virtual int indexOF(const T& theElement) const = 0;
virtual void erase(int index) =0;
virtual void insert(int theIndex,const T& theElment) = 0;
virtual void output(ostream &out) const =0;
};
template
struct chainNode{//结构体也能构造 成员,函数
T element;
chainNode *next;
chainNode(){}
chainNode(const T& element){ this->element= element;}
chainNode(const T& element,chainNode * next){
this->element= element;
this->next=next;
}
};
template
class chain : public linearList{//抽象类的派生类
public:
chain(int init =10);
chain(const chain&);
~chain();
bool empty() const {return listSize == 0;}//1
int size() const {return listSize ;} //1
T& get(int theIndex) const;//返回索引的元素
int indexOF(const T& theElment) const;//第一次出现的索引
void erase(int theIndex);
void insert(int theIndex,const T& theElement);
void output(ostream & out) const;
void swap(chain& theChain);//交换两个链表
// /习题
void setSize(int theSize);//若多于 则删除 1
void set(int theIndex,T theElement);//置换索引元素
int lastIndexOf(T theElement);//元素最后出现索引
void removeRange(int fromIndex,int toIndex);//删除索引范围内的所有节点
T& operator[](int index);
bool operator==(chain & x);
bool operator!=(chain& x);
bool operator<(chain& x);
void leftShift(int i);//左移动元素 (删除—)
void reverse();//颠倒元素顺序
void meld(chain& a,chain& b);//交替合并
void clean();//清空
void merge(chain& a,chain& b);//有序合并
void split(chain& a,chain& b);//分奇偶索引
void circularShift(int i);//向左循环索引
void insertSort();//链表排序
void binSort(int range);
///
friend ostream& operator<<(ostream& out,const chain& x){ x.output(out); return out;}
protected:
void checkIndex(int theIndex) const;
chainNode* firstNode;
int listSize;
};
template
class extendedLinearList: linearList{
public:
virtual ~extendedLinearList(){}
virtual void clear()=0; //清楚表的所有元素
virtual void push_back(const T& theElement) =0;//尾添法
protected :
chainNode * lastNode;//指向最后一个节点 还要提供改进的代码 ~inseat等
};
template
void
chain:: checkIndex(int theIndex) const{
if( theIndex<0 || theIndex >= listSize)
throw illegaParameterValue();
}
// 构造
template
chain:: chain(int init){
if(init <1){
ostringstream s; //该类能够根据内容自动分配内存,并且其对内存的管理也是相当的到位。 sprintf
s<<"initial capacity must >0 ";
throw illegaParameterValue();//为什么书上不行
}
firstNode = NULL;
listSize =0;
}
template
chain::chain(const chain& x){//赋值构造函数
listSize =x.listSize ;
if(listSize== 0){
firstNode = NULL;
return;
}
chainNode* sourceNode = x.firstNode;
firstNode= new chainNode (sourceNode->element);
sourceNode = sourceNode->next;
chainNode* targetNode =firstNode;
while(sourceNode != NULL){
targetNode->next = new chainNode(sourceNode->element);
targetNode = targetNode->next;
sourceNode = sourceNode->next;
}
targetNode->next = NULL;
}
template
chain::~chain(){
while(firstNode != NULL){
chainNode* deleteNode = firstNode;
firstNode=firstNode->next;
delete deleteNode;
}
}
template
T&
chain::get(int index) const{
checkIndex(index);
chainNode* currentNode= firstNode;
for(int i =0;inext; //就是指向 第index个节点
return currentNode->element;
}
template
int
chain::indexOF(const T& theElment) const{
chainNode* currentNode =firstNode;
for(int i =0;ielement ==theElment)
return i;
currentNode= currentNode->next;
}
return -1;
}
template
void
chain::erase(int theIndex){
checkIndex(theIndex);
chainNode* deleteNode;
if(theIndex == 0) {//是第一个节点
deleteNode = firstNode;
firstNode = firstNode->next;
}
else {
chainNode* preNode =firstNode;
for(int i=0;inext;
}
deleteNode = preNode->next;
preNode->next = preNode->next->next ;
}
delete deleteNode;
listSize--;
}
template
void
chain::insert(int theIndex,const T& theElement){
if(theIndex<0|| theIndex >listSize)
throw illegaParameterValue();
if(theIndex ==0)
firstNode= new chainNode(theElement,firstNode);
else{
chainNode* currentNode= firstNode;
for(int i=0;inext;
currentNode->next =new chainNode(theElement,currentNode->next); //37row
}
listSize++;
}
template
void
chain::output(ostream & out) const{
for(chainNode* currentNode =firstNode;currentNode!= NULL;currentNode=currentNode->next)
out<element <<' ';
out<
void
chain::setSize(int theSize){
checkIndex(theSize);
chainNode* pre= firstNode;
for( int i=0;inext;
chainNode* deleteNode;
pre->next=NULL;
chainNode* currentNode =pre->next;
while(currentNode!=NULL){
deleteNode =currentNode;
currentNode=currentNode->next;
delete deleteNode;
}
listSize=theSize;
}
template
void
chain::set(int theIndex,T theElement){
checkIndex(theIndex);
chainNode* current =firstNode;
for(int i=0;inext;
current->element = theElement;
}
template
int
chain::lastIndexOf(T theElement){
int index=0;
int i;
chainNode* current =firstNode;
for(i=0;ielement)
index =i;
current= current->next;
}
if(i
void
chain::removeRange(int fromIndex,int toIndex){
checkIndex(fromIndex);
checkIndex(toIndex);
chainNode * currentNode =firstNode,*lift,*right;
for(int i=0;inext;
}
right = currentNode;//确定尾部
if( fromIndex == 0){
lift=firstNode;
firstNode = right->next;
}
else {
currentNode =firstNode;
for(int i = 0;inext;
lift = currentNode->next;
currentNode->next = right->next;
}
while(lift!=right){//删除
currentNode = lift;
lift =lift->next;
delete currentNode;
}
delete lift;
listSize -= toIndex-fromIndex+1;
}
template
T&
chain::operator[](int index){
return get(index);
}
template
bool
chain::operator==(chain & x){
if(listSize != x.listSize)
return false;
chainNode *a=firstNode,*b = x.firstNode;
for(int i=0;ielement != b->element)
return false;
a=a->next;
b=b->next;
}
return true;
}
template
bool
chain:: operator!=(chain& x){
return ! (*this == x);
}
template
bool
chain::operator<(chain& x){
chainNode *a=firstNode,*b = x.firstNode;
while(a!=NULL && b!=NULL){
if(a->elementelement)
return true;
else if(a->element>b->element)
return false;
a=a->next;
b=b->next;
}
if( (a== NULL&& b==NULL) || b==NULL)
return false;
return true;
}
template
void
chain::swap(chain &theChain){//改指向就行
chainNode * temp = firstNode;
firstNode = theChain.firstNode;
theChain.firstNode = temp;
}
// template
// chain&
// arrayToChain(arrayList &array){
// chain temp(arrayList.size());//还是要自己插入
// for(int i =0;i
// arrayList&
// chainToArray(chain& chain){
// arrayList temp(chain.size());
// for(int i=0; i
void
reverse(chain& x){
x.reverse();
}
template
void
chain::reverse(){
chainNode * pre=NULL,*current=firstNode,*next; //指针换方向??
while(current !=NULL){
next = current->next;
current->next =pre;//反向
pre=current;
current=next;
}
firstNode = pre;
}
template
void
chain::leftShift(int i){//删除左边几个?
for(int k=0;k
chain&
meld(chain &a,chain &b){
chain *temp= new chain ;
int i=0,j=0,k=0;
while(iinsert(k++,a.get(i++));
temp->insert(k++,b.get(j++));
}
while(iinsert(k++,a.get(i++));
}
while(jinsert(k++,b.get(j++));
}
return *temp;
}
template
void
chain::meld(chain& a,chain& b){
int i=0,j=0,k=0;
while(i
void
chain::clean(){
chainNode* deleteNode;
while(firstNode != NULL){
deleteNode =firstNode;
firstNode=firstNode->next;
delete deleteNode;
}
}
template
void
chain::merge(chain& a,chain& b){
int i=0,j=0,k=0;
while(i
void
split(chain& a,chain& b,chain& c){
int i=0,j=0,k=0;
while(k
void
chain::split(chain&a,chain&b){
int i=0,j=0,k=0;
while(k
void
chain::circularShift(int num){
int i =0;
while(i
void
chain::insertSort(){
int i ,j,key;
for(i =0;i=0) && (key
void
chain::binSort(int range){//range 就相当于基数
chainNode ** bottom= new chainNode*[range+1];//桶底,头指针 指向节点
chainNode ** top = new chainNode*[range+1];//顶 尾指针
for(int i=0;i<=range;i++)
bottom[i]= NULL ; //初始所有桶为空
while(firstNode!=NULL){
int theBin = firstNode->element; //取数据 分到类桶中989
if(bottom[theBin] == NULL)
bottom[theBin]= top[theBin] = firstNode;
else{
top[theBin]->next =firstNode;
top[theBin]=firstNode; //尾巴移动
}
firstNode= firstNode->next;
}
chainNode* last =NULL ;
for(int theBin=0;theBin<=range;theBin++){
if(bottom[theBin] != NULL){
if(last ==NULL)//一个桶没合并
firstNode =bottom[theBin];
else
last->next = bottom[theBin];
last= top[theBin]; //移到当前桶尾部
}
if(last !=NULL )
last->next =NULL;
}
//利用原来链表空间
delete [] bottom;
delete [] top;
}
int main(){
chain a,b,c;
try{
for(int i=0;i<10;i++)
a.insert(i,9-i);//桶有范围的
for(int i=0;i<10;i++)
a.insert(i,9-i);
cout<
6.1
最终结果: {agbdeh}
6.2
O(listSize-theSize)
template
void
chain::setSize(int theSize){
checkIndex(theSize);
chainNode* pre= firstNode;
for( int i=0;inext;
chainNode* deleteNode;
pre->next=NULL;
chainNode* currentNode =pre->next;
while(currentNode!=NULL){
deleteNode =currentNode;
currentNode=currentNode->next;
delete deleteNode;
}
listSize=theSize;
}
6.3
O(theindex)
chain::set(int theIndex,T theElement){
checkIndex(theIndex);
chainNode* current =firstNode;
for(int i=0;inext;
current->element = theElement;
}
6.4
O(toIndex)
template
void
chain::removeRange(int fromIndex,int toIndex){
checkIndex(fromIndex);
checkIndex(toIndex);
chainNode * currentNode =firstNode,*lift,*right;
for(int i=0;inext;
}
right = currentNode;//确定尾部
if( fromIndex == 0){
lift=firstNode;
firstNode = right->next;
}
else {
currentNode =firstNode;
for(int i = 0;inext;
lift = currentNode->next;
currentNode->next = right->next;
}
while(lift!=right){//删除
currentNode = lift;
lift =lift->next;
delete currentNode;
}
delete lift;
listSize -= toIndex-fromIndex+1;
}
6.5
O(listSize)
template
int
chain::lastIndexOf(T theElement){
int index=0;
int i;
chainNode* current =firstNode;
for(i=0;ielement)
index =i;
current= current->next;
}
if(i
6.6
template
T&
chain::operator[](int index){
return get(index);
}
6.7
template
bool
chain::operator==(chain & x){
if(listSize != x.listSize)
return false;
chainNode *a=firstNode,*b = x.firstNode;
for(int i=0;ielement != b->element)
return false;
a=a->next;
b=b->next;
}
return true;
}
6.8
template
bool
chain:: operator!=(chain& x){
return ! (*this == x);
}
6.9
template
bool
chain::operator<(chain& x){
chainNode *a=firstNode,*b = x.firstNode;
while(a!=NULL && b!=NULL){
if(a->elementelement)
return true;
else if(a->element>b->element)
return false;
a=a->next;
b=b->next;
}
if( (a== NULL&& b==NULL) || b==NULL)
return false;
return true;
}
6.10
O(1)
template
void
chain::swap(chain &theChain){//改指向就行
chainNode * temp = firstNode;
firstNode = theChain.firstNode;
theChain.firstNode = temp;
}
6.11-6.12
template
chain&
arrayToChain(arrayList &array){
chain temp(arrayList.size());//还是要自己插入
for(int i =0;i
arrayList&
chainToArray(chain& chain){
arrayList temp(chain.size());
for(int i=0; i
不会迭代器类型
6.13
一样的 只不过变为成员函数。
复杂度都是O(listSize^2)
6.14
O(i) 一直为最好情况删除
template
void
chain::leftShift(int i){//删除左边几个?
for(int k=0;k
6.15-6.16
O(listSize) 设置三个指针 转向链表,而不是像数组一样互换值
template
void
reverse(chain& x){
x.reverse();
}
template
void
chain::reverse(){
chainNode * pre=NULL,*current=firstNode,*next; //指针换方向??
while(current !=NULL){
next = current->next;
current->next =pre;//反向
pre=current;
current=next;
}
firstNode = pre;
}
6.17-6.18
O(a.size+b.size)
template//非成员函数
chain&
meld(chain &a,chain &b){
chain *temp= new chain ;
int i=0,j=0,k=0;
while(iinsert(k++,a.get(i++));
temp->insert(k++,b.get(j++));
}
while(iinsert(k++,a.get(i++));
}
while(jinsert(k++,b.get(j++));
}
return *temp;
}
template
chain&
meld(chain &a,chain &b){
chain *temp= new chain ;
int i=0,j=0,k=0;
while(iinsert(k++,a.get(i++));
temp->insert(k++,b.get(j++));
}
while(iinsert(k++,a.get(i++));
}
while(jinsert(k++,b.get(j++));
}
return *temp;
}
template
void
chain::meld(chain& a,chain& b){
int i=0,j=0,k=0;
while(i
void
chain::clean(){
chainNode* deleteNode;
while(firstNode != NULL){
deleteNode =firstNode;
firstNode=firstNode->next;
delete deleteNode;
}
}
6.19-6.20
O(a.size+b.size)
template
void
chain::merge(chain& a,chain& b){
int i=0,j=0,k=0;
while(i
6.21-22
O(size)
template
void
split(chain& a,chain& b,chain& c){
int i=0,j=0,k=0;
while(k
void
chain::split(chain&a,chain&b){
int i=0,j=0,k=0;
while(k
6.23
O(num *size)
template
void
chain::circularShift(int num){
int i =0;
while(i
6.24-25
双向循环链表 ? 没明白什么意思 "当移动到p时“ 是指p尾结点的时候?
思路: 设置两个指针呗 一个指向前驱 一个 后继
6.26
最坏 O(size^3)
最好O(sisze^2)
template
void
chain::insertSort(){
int i ,j,key;
for(i =0;i=0) && (key
6.27
略 ,思路跟排序一样 只不过数组换成了链表 元素还是一样交换
时间复杂度应该都加了一个最高次 因为数组取元素为O(1) 而链表为O(n)
6.28 - 6.42 (带头结点的循环指针)
#include
using namespace std;
template
struct chainNode{//结构体也能构造 成员,函数
T element;
chainNode *next;
chainNode(){}
chainNode(const T& element){ this->element= element;}
chainNode(const T& element,chainNode * next){
this->element= element;
this->next=next;
}
};
template
class circularList{
public:
circularList();
~circularList();
void insert(T element);
void eraseNode(chainNode* x);
chainNode* rePoin(int index);//返回索引节点的指针
friend ostream& operator<<(ostream& out,const circularList& x){ x.output(out); return out;}
void output(ostream & out) const;
private:
chainNode *headerNode;
int listSize;
};
template
circularList::circularList(){
headerNode = new chainNode();
headerNode->next = headerNode;
listSize =0;
}
template
void
circularList::output(ostream & out) const{
chainNode* current;
for(current =headerNode->next;current!=headerNode;current=current->next)
out<element<<' ';
out<
circularList::~circularList(){
while(headerNode->next != headerNode){
chainNode* dele = headerNode->next;
headerNode ->next = dele->next;
delete dele;
}
}
template
void
circularList::insert(T value){//插入尾部
chainNode* pre=headerNode;
while(pre->next != headerNode)
pre=pre->next;
pre->next = new chainNode(value,headerNode);
listSize++;
}
template
void
circularList::eraseNode(chainNode* x){//只知道指向的指针 最好 O(1) 最坏 O(n)
if(x->next == headerNode){ //是最后一个节点 必须要遍历??
chainNode* pre = headerNode->next;
while(pre->next!=x)
pre=pre->next;
pre->next = headerNode;
delete x;
}
else {
x->element =x->next->element; //覆盖数据 删除下一节点
chainNode* dele = x->next;
x->next =x->next->next;
delete dele;
}
}
template
chainNode*
circularList:: rePoin(int index){
//返回索引节点的指针
chainNode* temp = headerNode->next;
for(int i =0;inext;
return temp;
}
int main(){
circularList a;
a.insert(5);
a.insert(888);
a.insert(666);
a.insert(88888);
a.eraseNode(a.rePoin(1));
a.eraseNode(a.rePoin(0));
cout<
重复的没做 思路是一样的 只是循环了
6.43 -6.61(双向循环链表等
#include
using namespace std;
template
struct Node{
T element;
Node *pre;
Node *next;
Node(){}
Node(const T& value){this->element = value;}
Node(const T& value,Node *pre, Node *next){
this->element =value;
this->next = next;
this->pre = pre;
}
};
template
class doubleCircularList{//带头结点的双向链表
public:
doubleCircularList();
~doubleCircularList();
void insert(T element);
friend ostream& operator<<(ostream& out,const doubleCircularList& x){ x.output(out); return out;}
void output(ostream & out) const;
void merge(doubleCircularList& x);//合并到表尾 ;
T get(int idnex);//如果小于size/2 左查找
private:
Node* headerNode;
int listSize;
};
template
doubleCircularList::doubleCircularList(){
headerNode = new Node();
headerNode->next=headerNode->pre=headerNode;
listSize++;
}
template
void
doubleCircularList::output(ostream & out) const{
Node* current;
for(current =headerNode->next;current!=headerNode;current=current->next)
out<element<<' ';
out<
doubleCircularList::~doubleCircularList(){
while(headerNode->next != headerNode){
Node* dele = headerNode->next;
headerNode ->next = dele->next;
delete dele;
}
}
template
void
doubleCircularList:: insert(T element){
Node* pre =headerNode->next;
while(pre->next != headerNode)
pre=pre->next;
pre->next = new Node(element,pre,headerNode);
headerNode->pre = pre->next;
listSize++;
}
template
void
doubleCircularList:: merge(doubleCircularList& x){
x.headerNode->next->pre = headerNode->pre;//b表前驱改为 a表尾部
headerNode->pre->next=x.headerNode->next;//a表尾部后驱 改为a表第一个
x.headerNode->pre->next = headerNode;//b 表最后改为 a表头
x.headerNode->next=x.headerNode;
x.headerNode->pre =x.headerNode;
}
template
T
doubleCircularList:: get(int index){
Node* current;
if (indexnext;
for(int i=0;inext;
}
else {
current=headerNode->pre;
for(int i =listSize-1;i>index;i--)
current=current->pre;
}
return current->element;
}
int main(){
doubleCircularList a,b;
a.insert(1);
a.insert(888);
a.insert(55);
b.insert(345);
cout<
方便很多 因为可以直接定位到最后一个节点O(1)
6.62
是稳定的 在链表前部的先入桶 合并也是先入链
6.63
自行测试
6.64(基数排序)
emplate
void
chain::binSort(int range,int d){//range 就相当于基数
chainNode ** bottom= new chainNode*[range+1];//桶底,头指针 指向节点
chainNode ** top = new chainNode*[range+1];//顶 尾指针
for(int i=0;i<=range;i++)
bottom[i]= NULL ; //初始所有桶为空
int div = pow(range,d);
int mod= pow(range,d+1);
while(firstNode!=NULL){
int theBin = (firstNode->element%mod) /div; //取数据 分到类桶中989 **重点在这基数排序
if(bottom[theBin] == NULL)
bottom[theBin]= top[theBin] = firstNode;
else{
top[theBin]->next =firstNode;
top[theBin]=firstNode; //尾巴移动
}
firstNode= firstNode->next;
}
chainNode* last =NULL ;
for(int theBin=0;theBin<=range;theBin++){
if(bottom[theBin] != NULL){
if(last ==NULL)//一个桶没合并
firstNode =bottom[theBin];
else
last->next = bottom[theBin];
last= top[theBin]; //移到当前桶尾部
}
if(last !=NULL )
last->next =NULL;
}
//利用原来链表空间
delete [] bottom;
delete [] top;
}
template
void
chain::radixSort(int range,int d){//基数r 按基数r分解的个数d
for(int i=0;i < d;i++){
binSort(range,i);
}
}
调用d次binSort 每次 2range(初始化+合并)+放桶listSize
一共 O(d(r+n)) 复杂度
6.51
一样的。
0-n^c-1 可以拆解成 n*n*n.....一共c个n相乘
每次比较一个基数n就行了
6.66
一样的三次桶排序。 先比优先级最小的
6.67-68
共线怎么计算最长两点?遍历Cn2?
极角不会
入栈 三个点为一组(第二个点大于180 则出栈不是极点
凸包算法详解(convex hull)_viafcccy的博客-CSDN博客_convex hull
(1条消息) 叉积(向量之间的计算)_Puppet__的博客-CSDN博客_叉积运算
#include
#include
using namespace std;
template
struct Node{
T x;
T y;
Node *pre;
Node *next;
Node(){}
Node(const T& x,const T& y){this->x = x;this->y =y;}
Node(const T& x,const T& y,Node *pre, Node *next){
this->x = x;
this->y =y;
this->next = next;
this->pre = pre;
}
};
template
class doubleCircularList{//带头结点的双向链表
public:
doubleCircularList();
~doubleCircularList();
void insert(const T& x,const T& y);
friend ostream& operator<<(ostream& out,const doubleCircularList& x){ x.output(out); return out;}
void output(ostream & out) const;
void merge(doubleCircularList& x);//合并到表尾 ;
T get(int idnex);//如果小于size/2 左查找
bool
checkCollinear();
void
angle(); //按极角排序
private:
Node* headerNode;
int listSize;
};
template
doubleCircularList::doubleCircularList(){
headerNode = new Node();
headerNode->next=headerNode->pre=headerNode;
listSize=0;
}
template
void
doubleCircularList::output(ostream & out) const{
Node* current;
for(current =headerNode->next;current!=headerNode;current=current->next)
out<x<<' '<y<
doubleCircularList::~doubleCircularList(){
while(headerNode->next != headerNode){
Node* dele = headerNode->next;
headerNode ->next = dele->next;
delete dele;
}
}
template
void
doubleCircularList:: insert(const T& x,const T& y){
Node* pre =headerNode->next;
while(pre->next != headerNode)
pre=pre->next;
pre->next = new Node(x,y,pre,headerNode);
headerNode->pre = pre->next;
listSize++;
}
template
void
doubleCircularList:: merge(doubleCircularList& x){
x.headerNode->next->pre = headerNode->pre;//b表前驱改为 a表尾部
headerNode->pre->next=x.headerNode->next;//a表尾部后驱 改为a表第一个
x.headerNode->pre->next = headerNode;//b 表最后改为 a表头
x.headerNode->next=x.headerNode;
x.headerNode->pre =x.headerNode;
}
template
T
doubleCircularList:: get(int index){
Node* current;
if (indexnext;
for(int i=0;inext;
}
else {
current=headerNode->pre;
for(int i =listSize-1;i>index;i--)
current=current->pre;
}
return current->element;
}
struct coordinate{
coordinate(){};
coordinate(double x,double y);
double x;
double y;
};
coordinate::coordinate(double x,double y){
this->x = x;
this->y = y;
}
template
Node&
interior_point(Node &a,Node& b,Node& c){
time_t t;
srand((unsigned)time(&t));
double x1 = (double)(rand()%100)/100;
double x2=(double)(rand()%100)/100;
if(x1+x2 > 1){
x1=1-x1;
x2=1-x2;
}
double x= a.x+x1*(b.x-a.x)+x2*(c.x-a.x);
double y= a.y+x1*(b.y-a.y)+x2*(c.y-a.y);
Node * temp = new Node(x,y);
return *temp;
}
template
bool
doubleCircularList::checkCollinear(){
if(listSize<3){
cout<<"error"<* current = headerNode->next;
double x1=current->x,y1=current->y;
current=current->next;
double x2=current->x,y2=current->y;
// double max=pow((x2-x1),2)+(pow(y2-y1),2);
// x-x1 * x2-x1 - y-y1 *y2-y1 ==0 共线
bool flag = 1;
for(current=current->next;current->next != headerNode;current=current->next){
if( (current->x-x1)*(x2-x1)-(current->y-y1)*(y2-y1) !=0){
flag = 0;
break;
}
}
if(flag == 0){
Node temp =interior_point(*headerNode->next,*headerNode->next->next,*current);
cout< a;
a.insert(2,5);
a.insert(2,5);
a.insert(2,5);
cout<< a.checkCollinear()<
6.69
(1条消息) 高精度运算——加减乘除(超详细模板)_Sqi的博客-CSDN博客
链表太麻烦了
6.70-71
只实现了加法
#include
using namespace std;
template
struct chainNode{//结构体也能构造 成员,函数
T element;
chainNode *next;
chainNode(){}
chainNode(const T& element){ this->element= element;}
chainNode(const T& element,chainNode * next){
this->element= element;
this->next=next;
}
};
struct polynomial{
int exp;//指数
int coeff;//系数
polynomial* next;
polynomial(){
exp =0; coeff =-1; next=NULL;
}
polynomial(int exp,int coeff){
this->exp=exp;
this->coeff = coeff;
}
};
template
class circularList{
public:
circularList();
~circularList();
void insert(T ,T);
int degree();//返回最高次
void intput();
circularList& add(circularList& b);
friend ostream& operator<<(ostream& out,const circularList& x){ x.output(out); return out;}
void output(ostream & out) const;
private:
struct polynomial *headerNode;
int listSize;
};
template
circularList::circularList(){
headerNode = new polynomial();
headerNode->next = headerNode;
listSize =0;
}
template
void
circularList::output(ostream & out) const{
polynomial* current;
for(current =headerNode->next;current!=headerNode;current=current->next){
cout<coeff <<"x^"<exp<<'+';
}
cout<<0;
out<
circularList::~circularList(){
while(headerNode->next != headerNode){
polynomial* dele = headerNode->next;
headerNode ->next = dele->next;
delete dele;
}
}
template
void
circularList::insert(T exp,T coeff){//插入尾部
polynomial* pre=headerNode;
while(pre->next != headerNode)
pre=pre->next;
pre->next = new polynomial(exp,coeff);
pre->next->next=headerNode;
}
template
int
circularList::degree(){
return headerNode->next->exp;
}
template
void
circularList::intput(){
cout<<"请输入个数?"<>listSize;
cout<<"请输入序列"<>exp>>cofeff;
insert(exp,cofeff);
}
}
template
circularList&
circularList::add(circularList& b){
polynomial *current = b.headerNode->next;
polynomial* x=headerNode->next;
if(current->exp>x->exp){//插入首
polynomial* temp = new polynomial(current->exp,current->coeff);
headerNode->next= temp;
temp->next = x;
current=current->next;
}
while(current!=b.headerNode){
for(;x!=headerNode&&x->exp >=current->exp;x=x->next){
if(current->exp == x->exp){
x->coeff+= current->coeff;
break;
}
if(x->next->expexp){
polynomial* temp = new polynomial(current->exp,current->coeff);
temp->next= x->next;
x->next = temp;
listSize++;
break;
}
}
current=current->next;
}
return *this;
}
int main(){
circularList a,b;
a.intput();
b.intput();
cout<
6.72
1) u次合并 每次都是原类+新类(一个) 所以总<= u+1
2)u次合并 都是 新类加新类(1+1) 所以单元素类至少为 n-2U
3) u-1 次合并后 就是包含所有单类了 不能再合并
6.73
#include
using namespace std;
struct equivNode{
int equivClass;
int size;
equivNode* next;
};
equivNode *node;
int n;
void init(int init_num){
n= init_num;
node = new equivNode[init_num+1];
for(int e= 1;e<=n;e++){
node[e].equivClass=e;
node[e].next =NULL;
node[e].size =1;
}
}
int
Find(int classNum){
return node[classNum].equivClass;//祖类 首节点就是当前大类的
}
void
unite(int a,int b){
if( Find(a) != Find(b)){
if(node[a].size > node[b].size){
swap(a,b);//改变较小类的
}
equivNode* k=node+a;
while(k->next!=NULL){
k->equivClass=b;
k=k->next;
}
k->equivClass=b;
//小类a 插入到b首元素之后
node[b].size+=node[a].size;
k->next = node[b].next;
node[b].next= node+a;
}
}
void show(){
for(int i=1;i<=5;i++){
cout<
6.74
因为都是截止时间往前推 ,先定优先级高的(必须在某时间段完成) 再排优先级低的
6.75
后者性能高
6.76:
//数组查并集
#include
using namespace std;
int *node;//整型数组
void init(int initNum){
node = new int[initNum+1];
for(int i =0;i<=initNum;i++)
node[i]=i;
}
int
find(int classNum){
if(node[classNum]== classNum)
return classNum;
else
return find(node[classNum]);//找到祖类
}
void
unite(int classA,int classB){
if( find(node[classA] ) != find( node[classB] ) ){//不属于同一类
node[classA]=classB; //默认归到B类
}
}
void show(){
for(int i=1;i<=5;i++){
cout<
查找 O(initNum)
合并 O(1)
初始化(initNUM)
一共(init )
6.77
见6.73
6.78
没看懂,服了!
第六章总结
线性表的链式描述:
单链表 /双链表
有无循环
有无头节点
排序:
桶排序:
基数排序(多次桶排序)
应用:
等价类
查并集
多项式
凸包(极角)
感觉应用很难 些脯肉
第七章
7.1:
i1*12+i2*4+i3*2+i4
7.2
一样的,* 剩下的维数
7.3
map(i1,i2,..,ik)= i1*u(k-1)+i2*u(k-2)+...+ik
U是剩下总维数
7.4
map(i1,i2,i3) = i3*u2+i2*u1+i1
7.5
一样的,是后面的*列维数
7.6
map(i1,i2,..,in)= ik*u(k-1)+i(k-1)*u(k-2)+...+i1
7.7
map(i1,i2)= (u1-i1-1)*u2+u2-i2
7.8
map(i1,i2)= u1*(u2-i2-1) +i1
7.9
实测 都是 sizeof(TYPE)*m*n
new 申请的二维数组才多出来一个指针对象
7.10
如果是new申请的 多 (n-1)维数*行数 个指针
维数很多时,一维数组快,可以直接计算一次地址就可以得到元素
7.11
同上
7.12
1)
( u1+u2+...u(k-1) ) *sizeof(*)+ u1u2u3..uk *sizeof(type)
// 每一个当前数组都储存指向内元素的指针,==里面元素的个数
直接一维数组的话 :
u1u2u3..uk *sizeof(type)
2)
比列: 假如指针和整型空间一样
1+ u1+u2+..u(k-1) / u1u2..uk
3)
访问指针次数过多时 ,而主映射下的一维数组实际只要计算一次
注意: 书上是错了吗? c和c++ 应该都一样 数组形式空间应该都是一样
都是通过步长来计算地址 ,只是类型不同,计算的地址也不同
7.13-14
关于对角线对称
7.15-7.16
#include
#include
using namespace std;
class illegaParameterValue{
public:
illegaParameterValue():
message("Illegal value"){}
illegaParameterValue(char * theMessage){
message = theMessage;
}
void outputMessage(){ cout<< message<
class matrix{
friend istream& operator>>(istream& in,const matrix& x){x.show(in); return in;}
friend ostream& operator<<(ostream& out,const matrix& x){ x.output(out); return out;}//在里面实例话 调用函数
public:
matrix(int theRows =0,int theColumns =0);
matrix(const matrix&);
~matrix(){delete [] element ;}
int rows(){return theRows;};
int Columns(){return theColumns;}
void output(ostream& )const;
void show(istream& )const;
matrix & tranpose();//转置矩阵
private:
int theRows;
int theColumns;
T *element;
};
template
matrix::matrix(int row,int col){
if((row<0||col<0)|| (row==0 &&col!=0)||(col==0&&row!=0))
throw illegaParameterValue();
element = new T [(row)*(col)];//映射为一维数组 且1开始表达
theRows =row;
theColumns = col;
}
template
void
matrix::output(ostream & out)const{
for(int i =0;i
void
matrix::show(istream & in)const {
for(int i =0;i>element[i];
}
template
matrix&
matrix::tranpose()
{ int i=0,j=0;
for(;ii)
swap(element[theRows*i+j],element[theColumns*j+i]);
swap(theColumns,theRows);
return *this;
}
int main(){
matrix a(2,2);
cin>>a;
a.tranpose();
cout<
7.17
二维的表达方法好像前面写过 略
感觉其实性能差不多(物理逻辑上都是一纬线性的)
只是表达方式不一样,可能映射成一维数组,只要计算一次下标(地址),会快一点
但个人认为二维的表达更清楚
7.18
脑补画图
1) 下三角
2) 上三角
3) 上三角
7.19
1) 2,4 狗窝
2) 自己画
3) 三对角矩阵
7.20
一样的咯
无需转置矩阵
复杂度都是 O(n) n为阶数
7.21
复杂度 O(n)
7.22
主要是找映射公示 蛮难找的 下标都是从 0开始
#include
#include
using namespace std;
class illegaParameterValue{
public:
illegaParameterValue():
message("Illegal value"){}
illegaParameterValue(char * theMessage){
message = theMessage;
}
void outputMessage(){ cout<< message<
class matrix{
friend istream& operator>>(istream& in,const matrix& x){x.input(in); return in;}
friend ostream& operator<<(ostream& out,const matrix& x){ x.output(out); return out;}//在里面实例话 调用函数
public:
matrix(int n=0);
matrix(const matrix&);
~matrix(){delete [] element ;}
void output(ostream& )const;
void input(istream& )const;
matrix & tranpose();//转置矩阵
private:
int n;
T *element;
};
template
matrix::matrix(int n){
if(n<0)
throw illegaParameterValue();
element = new T [3*n-2];//映射为一维数组 且1开始表达
this->n = n;
}
template
void
matrix::output(ostream & out)const{
int row,col;
for(row =0;row
void
matrix::input(istream & in)const {
for(int i =0;i>element[i];
}
int main(){
matrix a(4);
cin>>a;
cout<
7.23
公示改一下
cout<
7.24
不是 每行每列都有数字
7.25
感觉不规则二维数组没什么意义
空间都是一样的
一维数组方便寻址
二维的可能更方便阅读和找映射方式
7.26
#include
using namespace std;
template
class lowerTriangleAsIrregularArray{
public:
lowerTriangleAsIrregularArray(int n=0);
~lowerTriangleAsIrregularArray();
friend istream& operator>>(istream& in,const lowerTriangleAsIrregularArray& x){x.input(in); return in;}
friend ostream& operator<<(ostream& out,const lowerTriangleAsIrregularArray& x){ x.output(out); return out;}//在里面实例话 调用函数
void output(ostream& )const;
void input(istream& )const;
private:
int n;
T** element;
};
template
lowerTriangleAsIrregularArray::lowerTriangleAsIrregularArray(int n){
this->n=n;
element = new T*[n];
for(int i=1;i<=n;i++)
element[i-1]=new T[i];
}
template
lowerTriangleAsIrregularArray::~lowerTriangleAsIrregularArray(){
for(int i=0;i
void
lowerTriangleAsIrregularArray::input(istream & in) const{
for(int i=0;i>element[i][j];
}
}
template
void
lowerTriangleAsIrregularArray::output(ostream& out) const{
for(int i=0;i a(5);
cin>>a;
cout<
7.27
一样的咯
把指针数组指向的一维数组倒叙就行
7.28-7.29
#include
using namespace std;
template
class lowerTrianglerArray{
public:
lowerTrianglerArray(int n=0);
~lowerTrianglerArray();
friend istream& operator>>(istream& in,const lowerTrianglerArray& x){x.input(in); return in;}
friend ostream& operator<<(ostream& out,const lowerTrianglerArray& x){ x.output(out); return out;}//在里面实例话 调用函数
void output(ostream& )const;
void input(istream& )const;
T* tranpose();//转置成上三角映射的一维数组
private:
int n;
T* element;
};
template
lowerTrianglerArray::lowerTrianglerArray(int n){
this->n=n;
element = new T[ (n+1)*n/2];
}
template
lowerTrianglerArray::~lowerTrianglerArray(){
delete [] element;
}
template
void
lowerTrianglerArray::input(istream & in) const{//O(n^2)
for(int i=0;i< (n+1)*n/2;i++)
in>>element[i];
}
template
void
lowerTrianglerArray::output(ostream& out) const{//O(n^2)
for(int i=0;i
T*
lowerTrianglerArray::tranpose(){//O(n)
for(int start=0,end=(n+1)*n/2-1;start a(4);
cin>>a;
a.tranpose();
cout<
7.30
把其中一个主下三角转置成主上三角
这样就拼接成了一个方阵
把两个类的方法拼接一下就行了
7.31
下 *下 还是下三角矩阵
T**
lowerTrianglerArray::multiplication(lowerTrianglerArray& x){
T ** result = new T*[n];
for(int i=0; ii) {
result[i][j]= 0;
}
else if( i== j){
result[i][j]= element[(i+1)*i/2+j] * x. element[(i+1)*i/2+j];
}
else {
for(int k=j;k
O(n^3) 少了一些情况罢了
7.32
没有特殊性了
分两种情况{
i>= j 按行次数
i
}
for(k=0;k
7.33
略
总元素是 n*n/2
(i,j) == (j,i) 应该很简单
7.34
1) 按行压缩
2) n*n方阵 看成三排 重复两个 --> 3n-2
3)
#include
using namespace std;
template
class cMatrix{
public:
cMatrix(int n=0);
~cMatrix();
friend istream& operator>>(istream& in,const cMatrix& x){x.input(in); return in;}
friend ostream& operator<<(ostream& out,const cMatrix& x){ x.output(out); return out;}//在里面实例话 调用函数
void output(ostream& )const;
void input(istream& )const;
private:
int n;
T* element;
};
template
cMatrix::cMatrix(int n){
this->n=n;
element = new T[3*n-2];//c
}
template
cMatrix::~cMatrix(){
delete [] element;
}
template
void
cMatrix::input(istream & in) const{//O(n^2)
for(int i=0;i<3*n-2 ;i++)
in>>element[i];
}
template
void
cMatrix::output(ostream& out) const{//O(n^2)
for(int i=0;i a(4);
cin>>a;
cout<
7.35
2)
当且仅当 i+j == n+1 时 元素才能不为0
其实就是副对角线,有n个元素
3) 按行存呗
4)
#include
using namespace std;
template
class antidiagonalMatrix{
public:
antidiagonalMatrix(int n=0);
~antidiagonalMatrix();
friend istream& operator>>(istream& in,const antidiagonalMatrix& x){x.input(in); return in;}
friend ostream& operator<<(ostream& out,const antidiagonalMatrix& x){ x.output(out); return out;}//在里面实例话 调用函数
void output(ostream& )const;
void input(istream& )const;
private:
int n;
T* element;
};
template
antidiagonalMatrix::antidiagonalMatrix(int n){
this->n=n;
element = new T[n];
}
template
antidiagonalMatrix::~antidiagonalMatrix(){
delete [] element;
}
template
void
antidiagonalMatrix::input(istream & in) const{//
for(int i=0;i>element[i];
}
template
void
antidiagonalMatrix::output(ostream& out) const{//
for(int i=0;i a(4);
cin>>a;
cout<
5)
存 O(n)
取? 打印是(n^2)
7.36
1)
T(i,j) == T(i-1,j-1). 其实就是平移到左上角那一个元素(每一条斜的平行线都是相同元素值)
-->递归到 第一行和第一列 的元素 ,而又重合了一个
所以2n-1
2)
按行来
3)
#include
using namespace std;
template
class toeplitzMatrix{
public:
toeplitzMatrix(int n=0);
~toeplitzMatrix();
friend istream& operator>>(istream& in,const toeplitzMatrix& x){x.input(in); return in;}
friend ostream& operator<<(ostream& out,const toeplitzMatrix& x){ x.output(out); return out;}//在里面实例话 调用函数
void output(ostream& )const;
void input(istream& )const;
T get(int i,int j) const;
void set(int i, int j,T value);
T** multiplication(toeplitzMatrix& x);
private:
int n;
T* element;
};
template
toeplitzMatrix::toeplitzMatrix(int n){
this->n=n;
element = new T[2*n-1];
}
template
toeplitzMatrix::~toeplitzMatrix(){
delete [] element;
}
template
void
toeplitzMatrix::input(istream & in) const{//
for(int i=0;i<2*n-1;i++)
in>>element[i];
}
template
void
toeplitzMatrix::output(ostream& out) const{//
for(int i=0;ij)//下区
cout<
T
toeplitzMatrix::get(int i,int j)const {
return i>j? element[n+i-j-1]:element[j-i];
}
template
void
toeplitzMatrix::set(int i,int j,T value){
i>j?element[n+i-j-1]=value:element[j-i]=value;
}
template
T**
toeplitzMatrix::multiplication(toeplitzMatrix& x){
T ** result = new T*[n];
for(int i=0; i a(4);
cin>>a;
cout<
4) 思路:
找到祖行 也就是第一行或第一列
i>j (i-j,0) 为祖
j>i (0,j-i) 为祖
j= i (0,0 )为祖
然后套公示
7.37
1)
(2(a-1)+1)n-2(1+...+a-1)
= (n-1)*(2n-a) +n
(a<=n)
2)
|i-j|
3-4
a, 元素个数是对称分布的{
主对角线下边 =主对角线上边元素 = (n-1)*(2n-a)/2
主对角线 n个元素
}
b, 最少的一条斜线 有 n-a+1个元素
c、 左下角看行 i 来分组(斜线)
右上角 看列 j 来分组
d, 从左下往 主对角线 ,每条斜线多一个元素 直到n-1 个 (i>.j)
于是有:(n-a+1) +[(n-a+1)+1]+....+[(n-a+1)+(a-2-i)] 个元素总和 共有i项
求和 :
(2n-a-i)i/2
e. 从主对角线往上看斜线 ,每条斜线少一个元素 ,起始为a个元素 (j>i)
于是有:a+a-1+...+(a-j+1) 个元素总和 共有 i项
求和:
(2a-j+1)j/2
f.这些操作其实就是看小组的头成员(斜线分类的第一个元素)
偏移地址就看对应的行或列
总结:
if(i==j)
element[(n-1)*(2n-a)/2+i]
else if(i>j)
element[(2n-a-i)i/2+j]
else
element[(2a-j+1)j/2+i]
复杂度为O(1)
5)
不规则数组,O(1)
6)
一维数组应该快一点,但真的有必要吗????????
又难看懂,又要推倒公示 服了邹
7.38
1)略
2) 行列互换
3) 其中一个不为0 相加就不为0
7.39
1) 二维数组: 4+500*4+500*500*4
sparseMatrix : 8+2000*12+8+4
2)
8+12x+8+ >4m+4mn+4
x> (m+mn-1)/3
7.40
cols相当于偏移地址,只要确定了主行+偏移地址就行了
证明:
index1=i1*n+j1; (n为列数)
index2=i2*n+j2;
当i1=i2 看列偏移 j1
当i1
其他情况同理可证
7.41
get:
二分法 ,取arrayList数组中间下标
1,比较行
2,行对上,看列+-偏移量
复杂度logN
set :
1.查找到要插入的位置
2,元素后移插入
复杂度N
7.42
int pre = i*n+j ;
cin>>i>>j;
if(i*m+j<=pre|| value == 0)
throw....
7.43
用reset
terms.set(i,元素)
逐个复制插入
7.44
1)
m*j+i
2)-3)
一样的,只是映射不一样
7.45
可以设置一个数组 cloStart【】;
cloStart【i】表示第i列第一个元素的索引,用来查找b矩阵的列元素是否为 0
结果矩阵c :
(i,j) 对应矩阵的a i行,b j列 ,至少有一对元素都不为0 ,此位置才不为0
7.46
一样的,映射方式互换一下
7.47
1)
0,2,5,7
2)
用 rowStart【】代替
3)
略,太麻烦了
4)-6)
newSparseMatrix 运行时间是一样的 , 前者空间减少了
7.48
思路跟 7.45一样
7.49
互换行列
7.50
m*12+12x+4> 4m+4mn+4
x> (mn-2m)/3
7.51
就是邻接表
定位到边表对应的行,再数据链表(列) 查找对应
基本方法原理就是链表的插入和遍历
7.52
二维数组,数组元素是个struct,里面有行列等信息
就是把链表换成了指针储存
7.53
十字链表?
一个链表可以行遍历,也可以列遍历 ,并且循环 ;
1)
![数据结构 算法与应用(c++ 描述) 自练答案_第10张图片](http://img.e-com-net.com/image/info8/87739c52f9794381a576d577b68176a7.jpg)
2)
4+(5*4)*x> 4M+4MN+4
X> (M+MN)/5
3)
先连接 right ,用一个数组记录列下标,再连接down
4)-5)
待调试
ListMatrix::input(istream& in) const{//O(n^2)
int i,j,k,col = head->col,row=head->row;
T value;
int pre;
verticalList **colIndex = new verticalList * [col*row/2];
for(int i =0;i *current;
current=head;//初始化
in>>i>>j>>value;
while(i*col+j>pre && value != 0&& i!=-1 && head->value<=col*row&&(i< col &&jright = new verticalList(i,j,value,head);//尾插 循环
head->value++;
///
for(k=0;kvalue-1;k++){// 已经储存 value-1个指针 第value个是NULL
int index= colIndex[k]->col*row+colIndex[k]->row;
if(j*row+ivalue],colIndex[k+1]);//向后移
break;
}
}
colIndex[k] = current;//这里错了 待调试
cout<value<<' '<right;
in>>i>>j>>value;
}
//链接down链表
current= head;
verticalList* prev=NULL;
for(int i=0;ivalue;i++){
current->down = colIndex[i];
prev = current;
current=current->down;
}
prev->down = head;
}
template
void
ListMatrix::output(ostream& out)const{//O(n)
verticalList *current =head->right;
cout<<"一共有"<value<<"个非0元素"<row<<' '<col<<' '<value<right;
}
cout<<"按列次序遍历:"<down;
while(current!=head){
cout<row<<' '<col<<' '<value<down;
}
}
template
void
ListMatrix::Transpose(){ // O(1)
verticalList * temp= head->down;
head->down= head->right;
head->right =temp ;
}
int main(){
ListMatrix a(10,10);
cin>>a;
a.Transpose();
cout<
第七章总结
本章主要讲了
1 矩阵的表示方法
数组
一维数组映射 (省空间)
行主映射
列主映射
斜线映射(带状,三对角矩阵)
二维数组 (多了 行指针
规则
不规则(每行数组元素个数不相同,)
链表 :
稀疏矩阵等,节省储存方便遍历
2. 特殊矩阵 p157
对角,上下三角矩阵,稀疏矩阵等
这些都可以通过一维数组映射来节省空间
各有优越点 ,对于特殊矩阵
二维数组能节省时间,如get set 都是O(1)
而一维映射,链表能节省空间,但会增加某些方法的时间,也能减少某些方法的时间复杂度
第八章
8.1
【ATAD】
8.2
【SSALC】
8.3
弹夹
8.4
[l1,x,3] [l2,x,2] [l3,x,1] [l4,x,0] 压入递归栈
[l1,x,3] [l2,x,2] [l3,x,1] 弹出 ,l为返回地址,其他为形参或局部变量
[l1,x,3] [l2,x,2]
[l1,x,3]
8.5-8.6
略 ,道理都是一样的
8.7
derivedArrayStack没写,基类懒得找了
思路应该差不多
#include
using namespace std;
class illegaParameterValue{
public:
illegaParameterValue():
message("Stack Empty!"){}
illegaParameterValue(char * theMessage){
message = theMessage;
}
void outputMessage(){ cout<< message<
class arrayStack;
template
class stack{
public:
virtual ~stack(){}
virtual bool empty() const =0;
virtual int size() const =0; //当前栈中元素个数
virtual T& top() =0;//返回栈顶元素引用
virtual void pop() =0;
virtual void push(const T& theElement ) =0;
virtual void input() = 0;// 输入
virtual void output() =0;//转为合适的输出串
virtual void HalfStack(arrayStack& b) =0;//分为两半
virtual void MergeStack(arrayStack& b) = 0;//合并两个栈 相对顺序不变 第二个栈为顶部
};
template
class arrayStack:public stack{
public:
arrayStack(int init =10);
~arrayStack(){delete [] stack;}
bool empty()const {return stackTop == -1;}//因为索引 0 为第一个元素
int size()const {return stackTop +1;}
T& top();
void pop();
void push(const T& theElement);
void input() ;
void output() ;
void HalfStack(arrayStack& b);
void MergeStack(arrayStack& b);
void ChangeArray();
private:
int stackTop;//栈顶 +1 = 当前元素个数
int arrayLength;//总容量
T *stack;
};
template
arrayStack::arrayStack(int init){
if(init<=0)
throw illegaParameterValue();
arrayLength = init;
stack = new T[arrayLength];
stackTop = -1;
}
template
T&
arrayStack:: top(){
if(empty())
throw illegaParameterValue();
return stack[stackTop];
}
template
void
arrayStack::pop(){
if(empty())
throw illegaParameterValue();
stack[stackTop--].~T();
}
template
void
arrayStack::ChangeArray(){
T *temp = new T [arrayLength*2];
copy(stack,stack+arrayLength-1,temp);//复杂度 O(arraylength)
delete [] stack;
arrayLength *=2;
stack = temp;
}
template
void
arrayStack::push(const T& theElement){
if(stackTop == arrayLength-1){
ChangeArray();//翻倍
}
stack[++stackTop]= theElement;
}
template
void
arrayStack:: input(){
T temp;
char a;
cout<<"是否输入数据(Y or y)"<>a;
while(a=='Y'||a=='y'){
cin>>temp;
push(temp);
cin>>a;
}
}
template
void
arrayStack::output(){
for(int i =0; i<=stackTop;i++){
cout<
void
arrayStack:: HalfStack(arrayStack& b){
if(stackTop<1)
throw illegaParameterValue();
copy(stack+(stackTop+1)/2,stack+stackTop+1,b.stack);
b.stackTop=stackTop/2;
stackTop=(stackTop-1)/2;
}
template
void
arrayStack::MergeStack(arrayStack& b) {
if(stackTop+b.stackTop+2>=arrayLength)
ChangeArray();
copy(b.stack,b.stack+b.stackTop+1,stack+stackTop+1);
stackTop += b.stackTop+1;
}
int main(){
try{
arrayStack a(10),b(10);
a.push(666);
a.push(2000);
b.push(999);
b.push(222);
a.output();
b.output();
a.MergeStack(b);
a.output();
}
catch(illegaParameterValue e) {
e.outputMessage();
return 1;
}
return 0;
}
7.8
个别push,数组已满,要扩容复制,为O(栈的大小)
不可能每次push操作都要扩张
平摊分析中
执行一系列数据结构操作所需要的时间是通过执行的所有操作求平均而得出的。平摊分析可以用来证明在一系列操作中,通过对所有操作求平均之后,即使其中单一的操作具有较大的代价,平均代价还是很小的。
平摊分析不牵涉到概率, 平摊分析保证在最坏情况下,每个操作具有的平均性能。
#算法 平摊分析——一种特殊的分析方法_Franklins_Fan的博客-CSDN博客
8.9
template
void
arrayStack::pop(){
if(empty())
throw illegaParameterValue();
if(stackTop< arrayLength/4){
T *temp = new T [arrayLength/2];
copy(stack,stack+stackTop,temp);
delete stack;
stack =temp;
arrayLength/=2;
}
else
stack[stackTop--].~T();
}
证明一样的
8.10
stackWithArrayList 在自己类中实现方法,可以不用多余步骤(如判断)
dervedArrayStack 可以直接使用基类方法,避免重写,但效率欠佳
8.11
以前好像写过,这里就不写了 一搜就有
注意: 当任意一栈顶+1(或-1) == 另一栈顶时 或 等于0 或等于 arrayLength-1 时
则已满
top1从左向右,top2从右向左
8.12-8.13
linkedStack
#include
#include
#include
using namespace std;
class arrayList;
class illegaParameterValue{
public:
illegaParameterValue():
message("Illegal value"){}
illegaParameterValue(char * theMessage){
message = theMessage;
}
void outputMessage(){ cout<< message<
class linkedStack;
template // 抽象类
class stack{
public:
virtual ~stack(){}
virtual bool empty() const =0;
virtual int size() const =0; //当前栈中元素个数
virtual T& top() =0;//返回栈顶元素引用
virtual void pop() =0;
virtual void push(const T& theElement ) =0;
virtual void input() = 0;// 输入
virtual void output() =0;//转为合适的输出串
virtual void HalfStack(linkedStack & b) =0;//分为两半
virtual void MergeStack(linkedStack & b) = 0;//合并两个栈 相对顺序不变 第二个栈为顶部
};
template
struct chainNode{//结构体也能构造 成员,函数
T element;
chainNode *next;
chainNode(){}
chainNode(const T& element){ this->element= element;}
chainNode(const T& element,chainNode * next){
this->element= element;
this->next=next;
}
};
template
class linkedStack : public stack{//抽象类的派生类
public:
linkedStack(int inin = 10);
linkedStack(const linkedStack&);//0
~linkedStack();
/
bool empty() const {return stackSize == 0;}
int size() const {return stackSize ;}
void pop();
chainNode popNode();
void pushNode(chainNode *theNode);
void push(const T& theElement);
T& top();
void input() ;
void output() ;
void HalfStack(linkedStack & b) ;
void MergeStack(linkedStack & b) ;
//
friend ostream& operator<<(ostream& out,const linkedStack& x){ x.output(out); return out;}
protected:
chainNode* stackTop;
int stackSize;
};
template
linkedStack::~linkedStack(){
while(stackTop != NULL){
chainNode* deleteNode = stackTop;
stackTop=stackTop->next;
delete deleteNode;
}
}
template
linkedStack:: linkedStack(int init){
stackTop = NULL;
stackSize =0;
}
template
void
linkedStack::pop(){
if(stackSize== 0)
throw illegaParameterValue();
chainNode* nextNode=stackTop->next;
delete stackTop;
stackTop = nextNode;
stackSize--;
}
template
chainNode
linkedStack::popNode(){
if(stackSize== 0)
throw illegaParameterValue();
chainNode* tempNode=stackTop;
stackTop = stackTop->next;
stackSize--;
return *tempNode;
}
template
void
linkedStack::pushNode(chainNode *theNode){
theNode->next=stackTop->next;
stackTop->next = theNode;
}
template
void
linkedStack::push(const T& theElement){
stackTop = new chainNode(theElement,stackTop);
stackSize++;
}
template
T&
linkedStack::top(){
return stackTop->element;
}
template
void
linkedStack:: input() {
T temp;
char a;
cout<<"是否输入数据(Y or y)"<>a;
while(a=='Y'||a=='y'){
cin>>temp;
push(temp);
cin>>a;
}
}
template
void
linkedStack::output(){
for(chainNode* currentNode =stackTop;currentNode!= NULL;currentNode=currentNode->next)
cout<element <<' ';
cout<
void
linkedStack:: HalfStack(linkedStack & b) {
chainNode* current=stackTop;
for(int i=0;inext;
}
b.stackTop=current->next;
current->next = NULL;
b.stackSize=stackSize;
stackSize/=2;
b.stackSize-=stackSize;
}
template
void
linkedStack::MergeStack(linkedStack& b){
chainNode* current=b.stackTop;
for(int i=0;inext;
current->next=stackTop;
stackTop=b.stackTop;
stackSize+=b.stackSize;
b.stackTop= NULL;
b.stackSize= 0;
}
int main(){
linkedStack a,b;
a.input();
a.HalfStack(b);
a.output();
b.output();
return 0;
}
8.14
有些方法简单很多,只需要改变指向就行了
不会容量加倍,因为是链表
8.15
#include
#include
using namespace std;
bool check(string s){
//遍历一次
string::iterator i=s.begin();
int a=0,b=0;
while(i!=s.end())
if(*i=='(')
a++;
else if( *i==')')
b++;
if(a!=b)
return false;
return true;
}
int main(){
string s;
cin>>s;
cout<
8.16
‘(’ 从右往左遍历
‘)’ 从左往右遍历,两个stack
void printMatchendPairs(string s){//8.17
arrayStack a,b;
int length= (int) s.size();
for(int i=0,j=length-1;ib.size()?b.size():a.size();
for(int i=0;i>s;
printMatchendPairs(s);
return 0;
}
8.17
多用几个栈呗
8.18
x->y
x->z
y->z
x->y
z->x
z->y
x->y
x->z
y->z
y->x
z->x
y->z
x->y
x->z
y->z
8.19
对于n==1 :
进入hanoi (1) ,由于n-1==0 进入两个内部循环(2)都没有执行具体步骤就返回了
对于n==2:
进入hanoi(1),n-1 == 1 进入内部循环(2) 1-1=0 ,进入内部循环(3)不满足返回
1->2->3->2->1> ,这时 已经全部移动到盘子2了
然后进入第一层hanoi的第二个内部循环,重复,全部移动到盘子2了
对于n==n:
进入n+1层hanoi不满足返回
1->2->...->n+1->n->n-1->...->1
8.20:
被移动的就是当前n的编号,多输出一个n就行了
8.21:
template
void
arrayStack::showState(){
for(int i=stackTop;i>=0;i--){
cout<
8.22
不用大的在下面
n+n-1 == 2n-1
void haha(int n,char x,char y,char z){
for(int i=0;i%c\n",x,z);
}
printf("%c->%c\n",x,y);
for(int i=0;i%c\n",z,y);
}
8.23
可以减少 内层循环的次数
当为n-1时n-1个次大盘子直接移动到到n-1个中转站 ,最大的移动到目标盘子,再将n-1个中转移动到目标
n-1 +1 +n-1== 2n-1
8.24
两个缓冲不行
8.25
都是[0,k-1]
分k=1时,和最好情况时
8.26
1)不能,如8.24
2) 是最少的,因为有n个逆序(相对输出的来说),且k是最低的轨道个数,失败k就会++
8.27
加一条判断 当stacktop==si-1时 则满,此栈不能再使用,另寻它栈
8.28
遍历检查时,调用show()
8.29
int group[n];
bool flag[n];
for(int i=0;i
一样大小的栈;
8.30
等价离线类 要点:
n个元素 -->n个关系表
种子数组out【n】
默认从第一个开始为种子,入等价栈
等价栈 者 ->要加入list【入元素】表中全部内容
直到栈为空(无新关联元素加入) 输出的就是一个等价类
out数组全为true则遍历完毕
8.31
///书上打的 不知道哪里错了 说内存溢出
int n,r;
cout<<"enter number of elements"<>n;
if(n<2){
cout<<"Too few elements"<>r;
if(r<1){
cout<<"too few relations"< *list = new arrayStack [n+1];
int a,b;//关系队r
for(int i=1;i<=r;i++){//几个元素 几个表
cout<<"enter next relation/pair"<>a>>b;
if( (a<1||a>n)|| (b<1||b>n) )
throw illegaParameterValue();
list[a].push(b);
list[b].push(a);
}
arrayStack unprocessedList; //等价类临时栈
bool *out =new bool[n+1];//种子数组 当且仅当全部为true 为结束
for(int i=1; i<=n;i++)
out[i]= false;
//步骤2
for( int i=1;i<=n;i++)
if(!out[i] ){
cout<<"next class is:"<要加入list【入元素】表中全部内容
int q=list[j].top();
list[j].pop(); //相当于移动到临时栈
if(!out[q]){
cout<
int a,b;//关系队r
for(int i=1;i<=r;i++){//几个元素 几个表
cout<<"enter next relation/pair"<>a>>b;
if( (a<1||a>n)|| (b<1||b>n) )
throw illegaParameterValue();
list[a].push(b);
list[b].push(a);
}
8.32
具体实现方法不一样,但调用方法一样(都是调用成员函数empty()等)
数组肯定快一点
8.33
C++控制输出的字体颜色_幻欢子-CSDN博客_c++字体颜色
C++中发声函数Beep详解_v1t1p9hvbd的博客-CSDN博客
maze
#include
#include "windows.h"//macOs下没有
struct position{
int row;
int clo;
};
arrayStack *path ;//路线栈
int **maze;//矩阵
void welcome(){
// Beep(523,400);//do
// SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED |
// FOREGROUND_BLUE);//设置红色和蓝色相加
// cout<<" -----------------"<>size;
if(size<1)//
cout<<"error"<>i>>j;
while(i!=-1){
if(i>size+1||i<1||j>size+1||j<1){
cout<<"Cross the border ,re enter"<>i>>j;
continue
;
}
maze[i][j]=1;
cin>>i>>j;
}
for(int i=0;i<=size+1;i++){//show
for(int j=0;j<=size+1;j++)
cout<;
/书上有懒得复制
return true;
}
void outputPath(){
while(path->size()!=0){
cout<top().row<<" "<top().clo<pop();
}
cout<<"output END"<
8.34
struct position{
int row;
int col;
};
position next,here;
int option;
position offset[7];
offset[0].row=0;offset[0].col=1;
offset[1].row=1;offset[0].col=0;
offset[2].row=0;offset[0].col=-1;
offset[3].row=-1;offset[0].col=0;
offset[4].row=-1;offset[0].col=-1;//左上
offset[5].row=-1;offset[0].col=1;//右上
offset[6].row=1;offset[0].col=-1;//左下
offset[7].row=1;offset[0].col=1;//右下
//。。。对于返回下一次移动
if(next.row==here.row)
option =2 +next.col-here.col;
else if(next.col=here.col)
option= 3+next.row-here.row;
else if(next.row+1==here.row){
if(here.col=next.col+1)
option=6;
else option=5;
}
else {
if(next.row+1==here.row)
option = 8;//所有情况全无
else option=7;
}
8.35
m^2-1-blocked
8.36
思路应该是这样 ,但哪里错了呢 ,待调试
bool findPath(int i,int j,int size){
if(i>size|| j>size || i<1 || j<1 ||maze[i][j]==1)
return 0;
maze[i][j]=1;//先堵住防止返回
if(i==size&&j==size)//到目标点提前结束
return 1;
//递归部分
if( findPath(i,j+1,size) ){
cout<
8.37
网站呢 ,也没说 服了
8.38
从右往左遍历data
若为空则压入当前
循环 比较当前下标元素的值和栈顶下标元素的值 ,出栈直到大于当前或为空,押入当前
,由于从右向左,就是左边最靠近且大于的值
注意:栈a压入的是下标
最终a栈剩下的就是不符合条件的,由于一开始已经全部初始化为-1,无需弹出操作
nt main(){
int data[]={6,2,3,1,7,4};
int n=sizeof(data)/sizeof(data[0]);
int lastAsBig[n];
for(int i=0;i a(n);
for(int i=n-1;i>=0;i--){
if(a.empty()){
a.push(i);//押入下标
continue;
}
if(data[a.top()]>data[i])
a.push(i);
else{
while(!a.empty()&&data[a.top()]
第八章总结
本章主要讲了栈的形式,结构,应用等
a LIFO
b 分为 数组和链表两种实现方法,总体性能来讲还是数组占优,因为链表还多了很多指针
应用:
hanoi
列车调度
找迷宫
这些都可以用栈的思想来实现,也可以用递归。
感觉有一种分而治之的思想,向下延伸,不行再退回前一步
感悟:
界面的设计很重要,如何设计欢迎界面,如何播放音乐,输出图片?
这些都是要学习的,可能比程序本身更重要更繁琐
今天20岁咯,越努力越幸运
-----21/10/19
第九章
9.1
DATA
9.2
医院挂号
9.3
双开门电梯
9.4
离线等价类等价栈加入元素时
9.5
1) 合并待调试
#include
using namespace std;
template
class arrayQueqe;
template
class Queqe{
public:
virtual ~Queqe(){}
virtual bool empty() const =0;
virtual int size() const =0;
virtual T& Front()=0;
virtual T& Back()=0;
virtual void pop()=0;
virtual void push(const T& theElement) =0;
virtual void input()=0;
virtual void output()=0;
virtual void HalfQueqe(arrayQueqe& b) =0;//分为两半
virtual void MergeQueqe(arrayQueqe& b)=0;//合并
};
template
class arrayQueqe:public Queqe{
public:
arrayQueqe(int init =10);
~arrayQueqe(){delete [] Queqe;}
bool empty()const {return front==back;}
int size()const ;
void pop();
void push(const T& theElement);
void ChangeArray();
T& Front() {return front;}
virtual T& Back() {return back;}
void input();
void output();
void HalfQueqe(arrayQueqe& b);
void MergeQueqe(arrayQueqe& b);
private:
int front;
int back;
int arrayLength;
T *Queqe;
};
template
arrayQueqe::arrayQueqe(int init){
front=back=0;//[front+1] 是第一个元素的位置
Queqe = new T[init];
arrayLength = init;
}
template
int
arrayQueqe::size()const{
if(back>=front)
return back-front;
else
return back+arrayLength-front;
}
template
void
arrayQueqe::pop(){
if(front== back){
cout<<"error!";
exit(1);
}
front=(front+1)%arrayLength;
Queqe[front].~T();
}
template
void
arrayQueqe::push(const T& theElement){
if( (back+1)%arrayLength== front)
ChangeArray();
back=(back+1)%arrayLength;
Queqe[back]= theElement;
}
template
void
arrayQueqe::ChangeArray(){
T* newQueqe= new T[2*arrayLength];
int start=(front+1)&arrayLength;//第一个元素的位置
if(start<2){ //说明front为0 并没有循环数组
copy(Queqe+start,Queqe+start+arrayLength-1,newQueqe);
}
else {
copy(Queqe+start,Queqe+arrayLength,newQueqe);
copy(Queqe,Queqe+back+1,newQueqe+arrayLength-start);
}
front= 2*arrayLength-1;//默认新数组最后一个 第一个下标为【0】
back=arrayLength-2; //arrayLength-1-1
arrayLength*=2;
delete[]Queqe;
Queqe = newQueqe;
}
template
void
arrayQueqe::input(){
T value;
char c;
cout<<"是否输入数据(Y|y)"<>c;
while(c=='y'||c=='Y'){
cout<<"请输入数据"<>value;
push(value);
cout<<"是否输入数据(Y|y)"<>c;
}
}
template
void
arrayQueqe::output(){
if(back>=front){
for(int i=front+1;i<=back;i++)
cout<
void
arrayQueqe::HalfQueqe(arrayQueqe& b){
arrayQueqe* temp=new arrayQueqe(arrayLength);
int start=front+1;
if(back>=front){
while(start<=back){
temp->push(Queqe[start++]);
if(start>back)
break;
b.push(Queqe[start++]);
}
}
else {
while(startpush(Queqe[start++]);
if(start>=arrayLength)
break;
b.push(Queqe[start++]);
}
//前面一段
if( (arrayLength-1-front) %2==0)//下一个为奇 插入temp
for(int i=0;i<=back;){
temp->push(Queqe[i++]);
if(i>back)
break;
b.push(Queqe[i++]);
}
else
for(int i=0;i<=back;){
b.push(Queqe[i++]);
if(i>back)
break;
temp->push(Queqe[i++]);
}
}
delete[] Queqe;
Queqe=temp->Queqe;
back=temp->Back();
front=temp->Front();
cout<
void
arrayQueqe::MergeQueqe(arrayQueqe& b){//待调试
int newSize=size()+b.size()+1;
arrayQueqe* temp=new arrayQueqe(newSize);
int i=front+1,j=b.front+1;
int i1=0,j1=0;
while(i1==back+1||i==back+1||j==b.back+1||j1==b.back+1){
if(back>=front){
temp->push(Queqe[i++]);
}
else if(ipush(Queqe[i++]);
else{
temp->push(Queqe[i1++]);
}
if(b.back>=b.front){
temp->push(Queqe[j++]);
}
else if(jpush(Queqe[j++]);
else{
temp->push(Queqe[j1++]);
}
}
//插入剩下的 i==back 或 i1==back&&(i==length)
if(i>back+1){
while(ipush(Queqe[i++]);
while(i1<=back)
temp->push(Queqe[i1++]);
}
if(j>b.back+1){
while(jpush(Queqe[j++]);//尾部加入
while(j1<=back)
temp->push(Queqe[j1++]);
}
temp->output();
}
int main(){
arrayQueqe a(3),b;
a.push(1);
a.push(2);
a.push(3);
b.push(666);
a.MergeQueqe(b);
cout<
2)
差不多
9.6
肯定循环数组效率高 插入删除为O(1) 即使少数为O(元素个数)
9.7
“队列的容量与数组大小相同?”
那 初始值 quenueSize = 0;
Back=(quenueFront+quenueSize-1)%quenueSize;
9.8
相当于设置一个哨兵;
初始值 bool lastop= 0;(相当于pop了一次 ,一定不为满 ),若push 设置为1 pop为0
if(front==back && lastop==0)
为空
if(front==back && lastop==1)
为满
9.9
#include
using namespace std;
template
class arraydeque;
template
class deque{
public:
virtual ~deque(){}
virtual bool empty() const =0;
virtual int size() const =0;
virtual T& Front()=0;
virtual T& Back()=0;
virtual void pop_front()=0;
virtual void push_front(const T& theElement) =0;
virtual void pop_back()=0;
virtual void push_back(const T& theElement) =0;
};
template
class arraydeque:public deque{
public:
arraydeque(int init =10);
~arraydeque(){delete [] deque;}
bool empty()const {return front==back;}
int size()const ;
void pop_front();
void push_front(const T& theElement) ;//0
void pop_back();//0
void push_back(const T& theElement) ;
void ChangeArray();
T& Front() {return front;}
T& Back() {return back;}
void output();
private:
int front;
int back;
int arrayLength;
T *deque;
};
template
void
arraydeque::output(){
if(back>=front){
for(int i=front+1;i<=back;i++)
cout<
arraydeque::arraydeque(int init){
front=back=0;//[front+1] 是第一个元素的位置
deque = new T[init];
arrayLength = init;
}
template
int
arraydeque::size()const{
if(back>=front)
return back-front;
else
return back+arrayLength-front;
}
template
void
arraydeque::pop_front(){
if(front== back){
cout<<"error!";
exit(1);
}
front=(front+1)%arrayLength;
deque[front].~T();
}
template
void
arraydeque::pop_back(){
if(front== back){
cout<<"error!";
exit(1);
}
back= back-1<0?arrayLength-1:back-1;
}
template
void
arraydeque::push_front(const T& theElement){
if( (back+1)%arrayLength== front)
ChangeArray();
if( front
void
arraydeque::push_back(const T& theElement){
if( (back+1)%arrayLength== front)
ChangeArray();
back=(back+1)%arrayLength;
deque[back]= theElement;
}
template
void
arraydeque::ChangeArray(){
T* newdeque= new T[2*arrayLength];
int start=(front+1)&arrayLength;//第一个元素的位置
if(start<2){ //说明front为0 并没有循环数组
copy(deque+start,deque+start+arrayLength-1,newdeque);
}
else {
copy(deque+start,deque+arrayLength,newdeque);
copy(deque,deque+back+1,newdeque+arrayLength-start);
}
front= 2*arrayLength-1;//默认新数组最后一个 第一个下标为【0】
back=arrayLength-2; //arrayLength-1-1
arrayLength*=2;
delete[]deque;
deque = newdeque;
}
int main(){
arraydeque a(3),b;
a.push_back(5);
a.push_back(6);
a.push_front(666);
a.push_front(666);
a.pop_back();
a.output();
cout<
9.10-9.11
不太懂继承 ,直接调用基类arrayDeque的方法就行了,好像也不用新成员
复杂度就是对应方法的复杂度
#include
using namespace std;
template
class arraydeque;
template
class deque{
public:
virtual ~deque(){}
virtual bool empty() const =0;
virtual int size() const =0;
virtual T& Front()=0;
virtual T& Back()=0;
virtual void pop_front()=0;
virtual void push_front(const T& theElement) =0;
virtual void pop_back()=0;
virtual void push_back(const T& theElement) =0;
};
template
class stack{
public:
virtual ~stack(){}
virtual bool empty() const =0;
virtual int size() const =0; //当前栈中元素个数
virtual T& top() =0;//返回栈顶元素引用
virtual void pop() =0;
virtual void push(const T& theElement ) =0;
virtual void input() = 0;// 输入
virtual void output() =0;//转为合适的输出串
};
template
class arraydeque:public deque{
public:
arraydeque(int init =10);
~arraydeque(){delete [] deque;}
bool empty()const {return front==back;}
int size()const ;
void pop_front();
void push_front(const T& theElement) ;//0
void pop_back();//0
void push_back(const T& theElement) ;
void ChangeArray();
T& Front() {return front;}
T& Back() {return back;}
void output();
private:
int front;
int back;
int arrayLength;
T *deque;
};
template
class dequeStack:public arraydeque{//多重继承 逗号隔开
//直接调用基类方法就行了
};
template
void
arraydeque::output(){
if(back>=front){
for(int i=front+1;i<=back;i++)
cout<
arraydeque::arraydeque(int init){
front=back=0;//[front+1] 是第一个元素的位置
deque = new T[init];
arrayLength = init;
}
template
int
arraydeque::size()const{
if(back>=front)
return back-front;
else
return back+arrayLength-front;
}
template
void
arraydeque::pop_front(){
if(front== back){
cout<<"error!";
exit(1);
}
front=(front+1)%arrayLength;
deque[front].~T();
}
template
void
arraydeque::pop_back(){
if(front== back){
cout<<"error!";
exit(1);
}
back= back-1<0?arrayLength-1:back-1;
}
template
void
arraydeque::push_front(const T& theElement){
if( (back+1)%arrayLength== front)
ChangeArray();
if( front
void
arraydeque::push_back(const T& theElement){
if( (back+1)%arrayLength== front)
ChangeArray();
back=(back+1)%arrayLength;
deque[back]= theElement;
}
template
void
arraydeque::ChangeArray(){
T* newdeque= new T[2*arrayLength];
int start=(front+1)&arrayLength;//第一个元素的位置
if(start<2){ //说明front为0 并没有循环数组
copy(deque+start,deque+start+arrayLength-1,newdeque);
}
else {
copy(deque+start,deque+arrayLength,newdeque);
copy(deque,deque+back+1,newdeque+arrayLength-start);
}
front= 2*arrayLength-1;//默认新数组最后一个 第一个下标为【0】
back=arrayLength-2; //arrayLength-1-1
arrayLength*=2;
delete[]deque;
deque = newdeque;
}
int main(){
dequeStack a;
a.push_back(6);
a.push_back(5);
a.push_back(666);
a.pop_back();
a.output();
cout<
9.12-9.13
没用基类 ,懒得找了 ,合并和插入以前章节写过不写了
#include
using namespace std;
template
struct chainNode{
T element;
chainNode *next;
chainNode(){}
chainNode(const T& element){ this->element= element;}
chainNode(const T& element,chainNode * next){
this->element= element;
this->next=next;
}
};
template
class Queqe{
public:
virtual ~Queqe(){}
virtual bool empty() const =0;
virtual int size() const =0;
// virtual T& Front()=0;
// virtual T& Back()=0;
virtual void pop()=0;
virtual void push(const T& theElement) =0;
virtual void input()=0;
virtual void output()=0;
// virtual void HalfQueqe() =0;//分为两半
// virtual void MergeQueqe()=0;//合并
};
template
class linkedQueue:public Queqe{//从前向后 back指向最后一个节点 ,back-》next 为NULL
public:
linkedQueue();
~linkedQueue();
bool empty() const{return theFront==theBack;}
int size() const{return listSize;}
// T& Front(){}
// T& Back(){}
void pop();
void push(const T& theElement) ;
void input();
void output();
private:
chainNode *theFront;
chainNode *theBack;
int listSize;
};
template
linkedQueue::linkedQueue(){
theFront=theBack=NULL;
listSize =0;
}
template
linkedQueue::~linkedQueue(){
chainNode * dele=theFront;
while(theFront != NULL){//不为空
theFront=theFront->next;
delete dele;
dele = theFront;
}
}
template
void
linkedQueue::push(const T& theElement){
chainNode *newNode= new chainNode(theElement,NULL);
if(listSize==0)
theFront =newNode;
else
theBack->next = newNode;
theBack= newNode;
listSize++;
}
template
void
linkedQueue::pop(){
if(listSize ==0){
cout<<"error!"< *nextNode= theFront->next;
delete theFront;
theFront= nextNode;
listSize--;
}
template
void
linkedQueue::output(){
chainNode *currentNode=theFront;
while(currentNode !=NULL){
cout<element<<' ';
currentNode=currentNode->next;
}
cout<
void
linkedQueue::input(){
T value;
char c;
cout<<"是否输入数据(Y|y)"<>c;
while(c=='y'||c=='Y'){
cout<<"请输入数据"<>value;
push(value);
cout<<"是否输入数据(Y|y)"<>c;
}
}
int main(){
linkedQueue a;
a.push(5);
a.push(666);
a.push(3);
a.pop();
a.output();
return 0;
}
9.14
测试总时间模板
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义0
///---------------------------
int main(){
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
for(int i=0;i<1000000;i++){
// 调用函数 0
}
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
cout<
#include
#include
#define MAX_ 1000
using namespace std;
// 测试的函数定义
#include
using namespace std;
template
class arrayQueqe;
template
class Queqe{
// public:
// virtual ~Queqe(){}
// virtual bool empty() const =0;
// virtual int size() const =0;
// virtual T& Front()=0;
// virtual T& Back()=0;
// virtual void pop()=0;
// virtual void push(const T& theElement) =0;
// virtual void input()=0;
// virtual void output()=0;
// virtual void HalfQueqe(arrayQueqe& b) =0;//分为两半
// virtual void MergeQueqe(arrayQueqe& b)=0;//合并
};
template
class arrayQueqe:public Queqe{
public:
arrayQueqe(int init =10);
~arrayQueqe(){delete [] Queqe;}
bool empty()const {return front==back;}
int size()const ;
void pop();
void push(const T& theElement);
void ChangeArray();
T& Front() {return front;}
virtual T& Back() {return back;}
void input();
void output();
void HalfQueqe(arrayQueqe& b);
void MergeQueqe(arrayQueqe& b);
private:
int front;
int back;
int arrayLength;
T *Queqe;
};
template
arrayQueqe::arrayQueqe(int init){
front=back=0;//[front+1] 是第一个元素的位置
Queqe = new T[init];
arrayLength = init;
}
template
int
arrayQueqe::size()const{
if(back>=front)
return back-front;
else
return back+arrayLength-front;
}
template
void
arrayQueqe::pop(){
if(front== back){
cout<<"error!";
exit(1);
}
front=(front+1)%arrayLength;
Queqe[front].~T();
}
template
void
arrayQueqe::push(const T& theElement){
if( (back+1)%arrayLength== front)
ChangeArray();
back=(back+1)%arrayLength;
Queqe[back]= theElement;
}
template
void
arrayQueqe::ChangeArray(){
T* newQueqe= new T[2*arrayLength];
int start=(front+1)&arrayLength;//第一个元素的位置
if(start<2){ //说明front为0 并没有循环数组
copy(Queqe+start,Queqe+start+arrayLength-1,newQueqe);
}
else {
copy(Queqe+start,Queqe+arrayLength,newQueqe);
copy(Queqe,Queqe+back+1,newQueqe+arrayLength-start);
}
front= 2*arrayLength-1;//默认新数组最后一个 第一个下标为【0】
back=arrayLength-2; //arrayLength-1-1
arrayLength*=2;
delete[]Queqe;
Queqe = newQueqe;
}
template
void
arrayQueqe::input(){
T value;
char c;
cout<<"是否输入数据(Y|y)"<>c;
while(c=='y'||c=='Y'){
cout<<"请输入数据"<>value;
push(value);
cout<<"是否输入数据(Y|y)"<>c;
}
}
///---------------------------
int main(){
arrayQueqe a(100000);
long double clocksPerMillis = double(CLOCKS_PER_SEC) /1000; //CLOCKS 是滴答数的一秒 、除以1k 就是一毫秒的滴答数字
long numberRepetitions =0;
clock_t startTime= clock();//返回目前为止的时间
for(int i=0;i<1000000;i++){
a.push(1);
}
for(int i=0;i<1000000;i++){
a.pop();
}
long double elapsedMillis= (clock()-startTime)/clocksPerMillis;
cout<
链表的
![数据结构 算法与应用(c++ 描述) 自练答案_第12张图片](http://img.e-com-net.com/image/info8/cd117cefbdff47cabbb3a26566c18f25.png)
数组的
初始化为10 和100000大小一样的
![数据结构 算法与应用(c++ 描述) 自练答案_第13张图片](http://img.e-com-net.com/image/info8/5c274804647c4309ae12c80d331e0e62.png)
结论: 可以看到数组比链表快了近 5倍
9.15
说实话,感觉题目内容很重复,就不写了
只是形参是个节点,方法内不用new
9.16-18
不写了 第六章全写过,细节改一下罢了
9.19
电路布线: 选择移动到下一个位置 ,上下左右并无特殊要求,可以用栈
图元识别: 同理可换
9.20
两个轨道不行
![数据结构 算法与应用(c++ 描述) 自练答案_第14张图片](http://img.e-com-net.com/image/info8/db5a65e057d24a3ba2ce808067420164.jpg)
9.21
可以 ,k条轨道上线是k个序列
假设k个全部递增 1,2,3,..k
2至k全部安排到k-1条缓冲带 然后依次输出
9.22
没看明白什么意思,si是给定的吗,那加条件就行了
9.23
#include
using namespace std;
bool showTrack(int length,int tracks,int *carArray){
int lastCar[tracks+1];
int whichTrack[length+1];
for(int i=0; i<=tracks;i++)
lastCar[i]=0;
for(int i=0;i<=length;i++)
whichTrack[i]=0;
int k=1;//当前要出编号
int theCar;
for(int i=1;i<=length;i++){
cout<lastCarNUM&& lastCarNUM>bestLast){
bestLast =lastCarNUM;
bestTrack =i;
}
}
else if(bestTrack== 0)//都不为空 且都不符合才不执行这 ,不然默认选择一个空队列
bestTrack=i;
}
if( bestTrack==0)
return false;
///1
whichTrack[theCar] =bestTrack;
lastCar[bestTrack]=theCar;
}
else {//输出并查看
cout<<"outCar:"<
9.24
思路一样 , 只是扫描方法不一样,栈要顶是最小的 ,底依次增大
队列 front 要最小,后面依次增大
9.25
自己照着书步骤来就行
9.26
struct position{
int row;
int col;
};
position *path ;//路线数组
int pathLength;
int **grid;//矩阵
int size;
position start,finish;
void showGrid();
void welcome(){
cout<<" -----------------"<>size;
if(size<1)//
cout<<"error"<>i>>j;
while(i!=-1){
if(i>size+1||i<1||j>size+1||j<1){
cout<<"Cross the border ,re enter"<>i>>j;
continue
;
}
grid[i][j]=1;
cin>>i>>j;
}
showGrid();
cout<<"enter Roadblock"<>start.row>>start.col;
if(start.row>size+1||start.row<1||start.col>size+1||start.col<1||grid[start.row][start.col]==1){
cout<<"Cross the border||Have obstacles"<>finish.row>>finish.col;
if(finish.row>size+1||finish.row<1||finish.col>size+1||finish.col<1||grid[finish.row][finish.col]==1){
cout<<"Cross the border||Have obstacles "< q;
position nbr;
position here=start;
grid[start.row][start.col]=2; //-2 为距离
int numOfNbers=4;//4个相邻 四种选择
//
position offset[4];
offset[0].row=0;offset[0].col=1;
offset[1].row=1;offset[1].col=0;
offset[2].row=0;offset[2].col=-1;
offset[3].row=-1;offset[3].col=0;
do{
for(int i=0;i=0;j--){
path[j]=here;
for(int i=0;i
9.27
void CleanMark(){
int numOfNbers=4;//4个相邻 四种选择
arrayQueqe q;
//
position offset[4];
offset[0].row=0;offset[0].col=1;
offset[1].row=1;offset[1].col=0;
offset[2].row=0;offset[2].col=-1;
offset[3].row=-1;offset[3].col=0;
here=start;
grid[start.row][start.col]=0;
do{
for(int i=0;i1){//标记了 但不走的路
grid[nbr.row][nbr.col]= 0;
if(nbr.col==finish.col&& nbr.row==finish.row)
break;
q.push(nbr);
}
}//for 循环完成已经把周围可走格子压入了q队列
if(nbr.col==finish.col&& nbr.row==finish.row)
break;
if(q.empty())
here=q.Front();
q.pop();
}while(1);
for(int i=0;i
9.28
设计模式和上题差不多 ,书上也有,不写了
另外怎么输出不同的体颜色呢?
9.29
感觉一样的,目的都是遍历使周围元素,时间复杂度也一样
9.30(括号匹配
不行,括号顺序不匹配了
9.31(管角
不行,因为顺时针遍历管角,满足则弹出一对(上一个遍历到但未匹配的),用队列就不是弹出一队了
9.32(离线等价类
可以 ,因为等价元素集合都一样,从哪开始寻找有关联(等价)都行
9.33
可以,没有顺序要求
9.34
思路:
1. 结构job也设置一个 changeTime,也有转换状态,每个工序之间也要等待时间
2.机器执行队列,执行前要检查是否工序处于转换状态,若处于则弹出调度到队尾(只有此工序则一直等待)---> (nowTime== arrivalTime+changeTime||第一道工序)&&机器不处于转换状态 才能执行此任务工序
3. 函数 changeState同时可以改变工序状态,若机器转换>工序转换时间 ,则只要改变机器状态(工序自然而然能执行),反之亦然
9.35
就不是离线了
设置一个全局变量Maxtime 为仿真截止时间 ,在运行的任务算未完成的
第九章总结
本章主要讲了队列及其相关应用
方式
a 分为数组和链式储存,总体来看数组效率较高
数组可以用不同的映射方式,比如循环数组 ,基本方法时间控制在O(1)
应用
列车重排
电路布线(最短路径):李式路由算法
分为距离标记 和 回溯路径标记两个部分
距离标记用队列(或栈)寻找可行的路,并标记距离(+1),循环添加至队列直到到 达目标
图元识别:感觉有点像寻找等价类的情况,一个颜色相当于一个等价类,循环寻找
工厂仿真:本章最复杂的问题
分为3个结构和一个类 task job machine eventList
每一个右相互关联,有.难度
第十章
10.1
自己看
10.2
电话簿,购票系统,搜索记录
查找操作都需要
10.3
任务表单的存取?
10.4
C++ 中的 hash_map, unordered_map_小肥羊快快跑-CSDN博客
10.5
注意: 1 结构体也要缺省构造函数
2 class 普通方法要加public ,不然访问不了
#include
using namespace std;
template
struct pairNode{//数对结构
K KEY;
E Element;
pairNode (){}
pairNode(pairNode& theNode){KEY=theNode.KEY;Element=theNode.elemeny;}
pairNode(K theKEY,E theElement){KEY=theKEY;Element=theElement;}
};
template
class dictionary{
public:
virtual ~dictionary(){}
virtual bool empty() const=0;
virtual int size() const=0;//返回字典中数对的个数
virtual pairNode< K,E >* find(K&) const =0;//返回匹配数对的指针 ,若无返回NULL
virtual void erase(const K&) =0;//删除匹配数对
virtual void insert( pairNode< K,E>& ) =0;//如果相同关键字则替换 ,无则插入
};
template
class sortedArrayList:public dictionary< K,E>{//顺序(关键字)数组方式
public:
sortedArrayList(int init=10);
~sortedArrayList(){delete [] array;}
bool empty()const{ return ListSize==0;}
int size()const {return ListSize;}
pairNode< K,E >* find( K&) const;
void erase(const K&);
void insert(pairNode& );
private:
int ListSize;
pairNode *array;
};
template
sortedArrayList::sortedArrayList(int init){
array= new pairNode [init];
ListSize =0;
}
template
pairNode< K,E >*
sortedArrayList::find( K&theKEY) const{
for(int i=0;i
void
sortedArrayList::erase(const K& theKEY){
int i;
for( i=0;i
void
sortedArrayList::insert( pairNode& theNode){
int i;
for(i=0;i a;
cout< node(5,666);
a.insert(node);
}
10.6
尾巴节点储存要操作的关键字
这样判断时,当theKey== current(尾部)->key 时就已经遍历结束
或者插入到最后时,直接尾部当插入的节点,尾指针指向新创建的节点
删除时,尾指针前移
10.7
template
int skipList::level(float p) const{
int temp= rand();//p为概率
float Rmax=RAND_MAX*p;//初始值为 1到 1/p
int lev=0;
while (temp>Rmax)
{
lev++;
Rmax+= Rmax*p;
}
return (lev<= maxLeve)? lev:maxLevel;
}
10.8
方法细节改一下
如:删除 ,找到目标值最边最右的值 跳出循环,然后开始向右遍历依次删除直到不相等
插入,相等时,不改变值,而是插入到相当序列中最后面
10.9
从0级开始删(必包含),向上遍历,利用next 和last 数组 ,删除各级别
时间复杂度O(maxLevel)
跳表总结:
a: 0-MAX级表
0级表就是初始链表,包含所有数对
i级链表每(p^-1)^i个元素取一个,其中p是i-1级与i级 数对个数的比值
i级链表有 N* p^i个 数对
MAX一般为 【log(p^-1) N】 其中N为总对数
b: 属于i级的数对,必属于0至(i-1) 的数对集合 --> i级是从i-1 级数对中取的
10.10
设置maxKey个桶就行了 ,每个桶最多容纳一个
10.11
#include
#include
using namespace std;
long threeToLong(string s){
if(s.length()!=3)
cout<<"error!"<
10.12
要点是long四个字节 ,每个字符储存在一个字节内,通过与0 为0 加位移 来取出数据
string
LongToString(long answer){
string s;
long temp;
temp=(answer&0xFF0000)>>16;
s.push_back(temp);
temp=(answer&0x00ff00)>>8;
s.push_back(temp);
temp=(answer&0x0000ff);
s.push_back(temp);
return s;
}
10.13
一般要求桶内元素为【r/b】 向上整取,和向下整取 才为均匀散列表
1)
不是 最后几个桶永远为0,不均匀
2) 不是 大部分落入偶数桶中 p249面原因
3) 不是 ,大部分奇数桶中,同理
4) 不是,桶太多了
10.14
一般要求取大于20的素数
1,2 是 都是大与20的素数
10.15
单纯的加起来就行了,不用移位
10.16
#include
#include
using namespace std;
bool isPrime( int num )
{
int tmp =sqrt( num);
for(int i= 2;i <=tmp; i++)
if(num %i== 0)
return 0;
return 1;
}
int
ToD(float a ){
if(a<20)
return 21;
int result=(int)a;
while(1){
if(isPrime(result) )
return result;
result++;
}
}
int main(){
cout<
10.17
装载因子 10/13 --> r/b
成功时 3.17次
失败时 9.89次
注意: 书上好像说反了 U是不成功的查找次数,S是成功时的平均查找次数
差别可能是数对的问题
10.18-10.20
算装载因子套公示就行了
10.21
1)
![数据结构 算法与应用(c++ 描述) 自练答案_第16张图片](http://img.e-com-net.com/image/info8/4d940fc89d2a45bbafdf41d83df25e5b.jpg)
接下去真不会了,数学不行
2)
不行,因为跟开始遍历的位置(表头)不会发生变化
10.22
#include
using namespace std;
float
Linear_detection_Un(float a){
return (1+1/ ((1-a)*(1-a)))/2; //10-3公示
}
float
Linear_detection_Sn(float a){
return (1+1/(1-a))/2; //10-4
}
float
Random_detection_Sn(float a){
return 1+a/2; // 1+a/2
}
int main(){
cout<<"Linear_Un/Sn:"<<"------"<<"Random_Sn"<1 时 Un= a*(a+3)/2(a+1)
// 小于1时, 平均搜索不可能大于每个桶的平均长度 Un<= a
}
10.23
#include
#include
using namespace std;
int
fun(float Sn,float n){
return n/(1-1/(2*Sn-1));//反解D
}
int
fun1(float Un,float n){
return n/(1-sqrt(1/(2*Un-1)) );
}
int main(){
cout<
10.24
【0,MaxElements】 个元素
那我就取MaxElements个桶呗,或者均匀散列表要求
10.25
错的,调
template
void
hashTable::changeTable(){//copy
pair** temp = new pair *[divisor*2+1];
for(int i=0;ifirst%divisor;
if(original!=a){
if(table[original]==NULL){
//如果原始桶为空则放入,
table[original]= table[a];
table[a]==NULL;
}
else {
int j=1;
while(table[(original+j)%divisor]!=NULL)
j++;
table[(original+j)%divisor]=table[a];
table[a]=NULL;
}
}
}
}
}
10.26
最坏O(divisor)
template
void
hashTable::erase(const K& theKey){
//删除一个后 把不在自己原始桶的都向前移,
int a=search(theKey);
cout<first%divisor;
if(original!=a){
if(table[original]==NULL)//如果原始桶为空则放入,
table[original]= table[a%divisor];
else
table[pre]=table[a%divisor];
table[a%divisor]=NULL;
pre=a%divisor;
}
}
}
}
template
void
hashTable::show(){
int i;
for(i=0;ifirst< a(6,1);
pair s(2,100),s1(4,101),s3(8,102),s4(11,103),s5(12,104),c(18,111);
a.insert(s);a.insert(s1);a.insert(s3);a.insert(s4);a.insert(s5);
a.erase(2);
a.erase(11);
a.insert(c);
a.erase(12);
a.show();
return 0;
}
10.27
相当于设置一个标志位 false为有数对,true 为空
不是通过检查是否为NULL 或等于本身来判断情况
10.28
就是向前向后探测,利用平方
散列表(四)冲突处理的方法之开地址法: 二次探测再散列的实现 - AlanTu - 博客园 (cnblogs.com)
10.29
冲突时,用另一个散列函数来寻找位置
Hash算法:双重散列 - 賣贾笔的小男孩 - 博客园 (cnblogs.com)
10.30
线性探测:要判断每一个元素是否为空,冲突时还要线性寻找
链式: 要遍历同一个桶的所有元素,且不能用下标来代替指针
10.31-32
自己套公式
10.33
上一章好像写过?
搜索时==表尾的自身值时表示搜索失败 ,不用与NULL比较
10.34
不就是基本链表操作吗,类似于邻接表,找到邻边,插入到右表
10.35-10.36
思路一样
尾结点共用一个 ,都指向这个就行了 ,同一个方法同一时间只能执行一个
10.37
1) 肯定不行啊,要指向不同个桶 就得要不同个头结点
2)没必要,又不是循环链表,遍历不到头结点去
3)思路一致
4) 头结点:避免特殊情况(插入在第一个,邻表要改)
尾结点:避免NULL的判断
推荐都不使用,就是纯粹,性能其实跟这些无伤大雅,检验NULL和检验
是否为尾值不是一样吗(插入到表尾除外
10.38
STL之list容器详解 - Sam大叔 - 博客园 (cnblogs.com)
list就是一个双向链表
链表的元素是一个链表
10.39
不用copy,先增加领边表,然后从第一个领边开始遍历域表,
不属于自己原始桶的移动到原始桶,思路和数组的一致
10.40
散列表的性能分析 - 计算机的探索者 - 博客园 (cnblogs.com)
肯定是开放定址法效率高一点 ,推荐使用STL hash_map,肯定比自己写效率高
10.41
a=n/b -->平均长度
无序,插入到右端,--> 遍历到底: 只有一种可能的范围使其失败
Un = 1/(i+1)*(i+i^2) = i=a;
Sn = 1+a/2
(与书p257一致),计算到表头的平均长度
10.42
![数据结构 算法与应用(c++ 描述) 自练答案_第17张图片](http://img.e-com-net.com/image/info8/27a8bdb13f704090997efe2393355149.jpg)
10.43
0123
1到13的累加=91 乘9个 -->
-->0+1+...+12+8
10.44
主要体现在查找和插入方面上
应该链表好一点,查找次数少
10.45
完全有可能,不重复的字符越多,字典数目就越大,且转换不成压缩码
10.46
可能
10.47
重新散列?可以减少查找的时间,当字典越长时,所需时间越多
自行实验
10.48
1) list选用arrayList
索引表选用链表,或Hash_table
2) 思路跟本章开头差不多 ,相当于Key是string类型
第十章总结
hash_table(总
#include
using namespace std;
// pair 自带的容器
template
class hashTable {
public:
hashTable(int theDiv=13,float theMaxFactor=0.8)
{
divisor=theDiv;
MaxFactor=theMaxFactor;
dSize=0;
table= new pair* [divisor];
for(int i=0;i* find(const K& theKey) const;
void insert(const pair& thePair);
int hash(const K& theKey);//用此函数代替
void changeTable();//2*size+1 超过定义因子
void erase(const K& theKey);
void show();
private:
pair** table;
int dSize;
int divisor;//也是默认桶的数量
float MaxFactor;//用户指定
//hash hash;
};
template
int
hashTable::hash(const K& theKey){
//默认就是整形 直接返回
return theKey;
}
template
int
hashTable::search(const K& theKey) const{
int i= theKey%divisor;
int j=i;
do{
if(table[j]==NULL || table[j]->first== theKey)
return j;
j=(j+1)%divisor;
}while(j!=i);
return j;
}
template
std::pair* //要加命名空间
hashTable::find(const K& theKey) const{
int b=search(theKey);
if(table[b]==NULL || table[b]->first != theKey)
return NULL;
return table[b];
}
template
void
hashTable::insert(const std::pair& thePair){
int b=search(thePair.first);
if(table[b]==NULL) {
table[b] = new pair(thePair);
dSize++;
}
else {
if( table[b]->first == thePair.first)
table[b]->second= thePair.second;
else {
cout<<"FULL!"<MaxFactor)
changeTable();
}
template
void
hashTable::changeTable(){//copy
pair** temp = new pair *[divisor*2+1];
for(int i=0;ifirst%divisor;
if(original!=a){
if(table[original]==NULL){
//如果原始桶为空则放入,
table[original]= table[a];
table[a]==NULL;
}
else {
int j=1;
while(table[(original+j)%divisor]!=NULL)
j++;
table[(original+j)%divisor]=table[a];
table[a]=NULL;
}
}
}
}
}
template
void
hashTable::erase(const K& theKey){
//删除一个后 把不在自己原始桶的都向前移,
int a=search(theKey);
cout<first%divisor;
if(original!=a){
if(table[original]==NULL)//如果原始桶为空则放入,
table[original]= table[a%divisor];
else
table[pre]=table[a%divisor];
table[a%divisor]=NULL;
pre=a%divisor;
}
}
}
}
template
void
hashTable::show(){
int i;
for(i=0;ifirst< a(6,1);
a.show();
return 0;
}
本章主要讲了 数对 的储存方法
--> 字典
![数据结构 算法与应用(c++ 描述) 自练答案_第18张图片](http://img.e-com-net.com/image/info8/965f09cce71e443394f79b7e6af8d2a4.jpg)
主要是hash表 ,用映射方式储存在空间中,大大减少方法时间 {
a. 映射函数 ,可以把任意类型的Key转换为整型值 以此来储存在表中
如string通过移位等转换为整型
b. 当冲突时,可以选择方法来避免冲突,如线性探测,双向探测,再散列等
c.常用的散列有除余法,应选择不小于20的素数
d.性能分析,有一套完整的公示 见10.17
e.链式hash表类似于邻接表
}
跳表 见10.9
还讲了LZW的压缩应用{10.42
利用前缀+c 制成压缩字典 ,储存在hash表中
解压时将前缀代码复原成原始子串,形成解压字典
}
第十一章
数据结构第十一章(二叉树及其他树)自练答案_万千只cnm&的博客-CSDN博客
第十二章
第十二章 优先队列_万千只cnm&的博客-CSDN博客
第十三章
第十三章 赢/输者树(选择树,决策树_万千只cnm&的博客-CSDN博客
第十四章
第十四章 搜索树_万千只cnm&的博客-CSDN博客
第十五章
第十五章 平衡搜索树(AVL 红黑 分裂 m插搜索树/ B+树_万千只cnm&的博客-CSDN博客
第十六章 图
第十六章 图_万千只cnm&的博客-CSDN博客
第十七章 贪婪算法
第十七章 贪婪算法_万千只cnm&的博客-CSDN博客
第十八章 分而治之
第十八章 分而治之(归并排序)_万千只cnm&的博客-CSDN博客
第十九章 动态规划
第十九章 动态规划(背包/矩阵链/顶点路径_万千只cnm&的博客-CSDN博客
第二十章 回溯法
第二十章 回溯法_万千只cnm&的博客-CSDN博客
第二十一章 分支定界
第二十一章 分支定界_万千只cnm&的博客-CSDN博客
总总结
终于看完了,后面几章有难度,如果想真正懂,还是得刷题
下一步准备学 linux 和html css JavaScript 和py 共勉
附:
五大常用算法:分治、动态规划、贪心、回溯和分支界定 - 小山药 - 博客园