一维与二维树状数组

一维与二维树状数组
一维与二维树状数组

昨天学了一下树状数组,随笔都写了一大半,结果一个不小心就把他给删了,哎。。。。。。今天就当是复习吧!再写一次。

如果给定一个数组,要你求里面所有数的和,一般都会想到累加。但是当那个数组很大的时候,累加就显得太耗时了,时间复杂度为O(n),并且采用累加的方法还有一个局限,那就是,当修改掉数组中的元素后,仍然要你求数组中某段元素的和,就显得麻烦了。所以我们就要用到树状数组,他的时间复杂度为O(lgn),相比之下就快得多。下面就讲一下什么是树状数组:

一般讲到树状数组都会少不了下面这个图:

下面来分析一下上面那个图看能得出什么规律:

据图可知:c1=a1,c2=a1+a2,c3=a3,c4=a1+a2+a3+a4,c5=a5,c6=a5+a6,c7=a7,c8=a1+a2+a3+a4+a5+a6+a7+a8,c9=a9,c10=a9+a10,

c11=a11........c16=a1+a2+a3+a4+a5+.......+a16。

分析上面的几组式子可知,当i 为奇数时,ci=ai ;当i 为偶数时,就要看i 的因子中最多有二的多少次幂,例如,6 的因子中有2 的一次幂,等于 2 ,所以c6=a5+a6(由六向前数两个数的和),4 的因子中有 2 的两次幂,等于4 ,所以c4=a1+a2+a3+a4(由四向前数四个数的和)。

(一)有公式:cn=a(n-a^k+1)+.........+an(其中k 为n 的二进制表示中从右往左数的0 的个数)。

那么,如何求a^k 呢?求法如下:

lowbit()的返回值就是2^k 次方的值。

求出来2^k 之后,数组c 的值就都出来了,接下来我们要求数组中所有元素的和。

(二)求数组的和的算法如下:

(1)首先,令sum=0,转向第二步;

(2)接下来判断,如果n>0 的话,就令sum=sum+cn转向第三步,否则的话,终止算法,返回sum 的值;

(3)n=n - lowbit(n)(将n的二进制表示的最后一个零删掉),回第二步。

代码实现:

(三)当数组中的元素有变更时,树状数组就发挥它的优势了,算法如下(修改为给某个节点i 加上x ):

(1)当i<=n 时,执行下一步;否则的话,算法结束;

(2)ci=ci+x ,i=i+lowbit(i)(在i 的二进制表示的最后加零),返回第一步。

代码实现:

树状数组是对一个数组改变某个元素和求和比较实用的数据结构。两中操作都是O(logn)。

在解题过程中,我们有时需要维护一个数组的前缀和S[i]=A[1]+A[2]+...+A[i]。

但是不难发现,如果我们修改了任意一个A[i],S[i]、S[i+1]...S[n]都会发生变化。

可以说,每次修改A[i]后,调整前缀和S[]在最坏情况下会需要O(n)的时间。

当n非常大时,程序会运行得非常缓慢。

因此,这里我们引入“树状数组”,它的修改与求和都是O(logn)的,效率非常高。

【理论】

为了对树状数组有个形象的认识,我们先看下面这张图。

如图所示,红色矩形表示的数组C[]就是树状数组。

这里,C[i]表示A[i-2^k+1]到A[i]的和,而k则是i在二进制时末尾0的个数,

或者说是i用2的幂方和表示时的最小指数。

(当然,利用位运算,我们可以直接计算出2^k=i&(i^(i-1)) )

同时,我们也不难发现,这个k就是该节点在树中的高度,因而这个树的高度不会超过logn。

所以,当我们修改A[i]的值时,可以从C[i]往根节点一路上溯,调整这条路上的所有C[]即可,

这个操作的复杂度在最坏情况下就是树的高度即O(logn)。

另外,对于求数列的前

n项和,只需找到n以前的所

有最大子树,把其根节点的C

加起来即可。

不难发现,这些子树的

数目是n在二进制时1的个

数,或者说是把n展开成2的

幂方和时的项数,

因此,求和操作的复杂

度也是O(logn)。

接着,我们考察这两种操作下标变化的规律:

首先看修改操作:

已知下标i,求其父节点的下标。

我们可以考虑对树从逻辑上转化:

如图,我们将子树向右对称翻折,虚拟出一些空白结点(图中白色),将原树转化成完全二叉树。

有图可知,对于节点i,其父节点的下标与翻折出的空白节点下标相同。

因而父节点下标p=i+2^k (2^k是i用2的幂方和展开式中的最小幂,即i为根节点子树的规模)

即p = i + i&(i^(i-1)) 。

接着对于求和操作:

因为每棵子树覆盖的范围都是2的幂,所以我们要求子树i的前一棵树,只需让i减去2的最小幂即可。

即p = i - i&(i^(i-1)) 。

至此,我们已经比较详细的分析了树状数组的复杂度和原理。

在最后,我们将给出一些树状数组的实现代码,希望读者能够仔细体会其中的细节。【代码】

求最小幂2^k:

int Lowbit(int t)

{

return t & ( t ^ ( t - 1 ) );

}

求前n项和:

int Sum(int end)

{

int sum = 0;

while(end > 0)

{

sum += in[end];

end -= Lowbit(end); }

return sum;

}

对某个元素进行加法操作:

void plus(int pos , int num) {

while(pos <= n)

{

in[pos] += num;

pos += Lowbit(pos);

}

}

当要频繁的对数组元素进行修改,同时又要频繁的查询数组内任一区间元素之和的时候

,

可以考虑使用树状数

组.

通常对一维数组最直接的算法可以在O(1)时间内完成一次修改,但是需要O(n)时间来进行一次查询.而树状数组的修改和查询均可在O(log(n))的时间内完成.

一、回顾一维树状数组

假设一维数组为A[i](i=1,2,...n),则与它对应的树状数组C[i](i=1,2,...n)是这样定义的:

C1 = A1

C2 = A1 + A2

C3 = A3

C4 = A1 + A2 + A3 + A4

C5 = A5

C6 = A5 + A6

C7 = A7

C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8

……

C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16 ......

(1)C[t]展开以后有多少项?由下面公式计算:

int lowbit(int t){//计算c[t]展开的项数

return t&(-t);

}

C[t]展开的项数就是lowbit(t),C[t]就是从A[t]开始往左连续求lowbit(t)个数的和.

(2)修改

比如修改了A3,必须修改C3,C4,C8,C16,C32,C64...

当我们修改A[i]的值时,可以从C[i]往根节点一路上溯,调整这条路上的所有C[]即可,对于节点i,父

节点下标p=i+lowbit(i)

//给A[i]加上x后,更新一系列C[j]

update(int i,int x){

while(i<=n){

c[i]=c[i]+x;

i=i+lowbit(i);

}

}

(3)求数列A[]的前n项和,只需找到n以前的所有最大子树,把其根节点的C加起来即可。

如:Sun(1)=C[1]=A[1];

Sun(2)=C[2]=A[1]+A[2];

Sun(3)=C[3]+C[2]=A[1]+A[2]+A[3];

Sun(4)=C[4]=A[1]+A[2]+A[3]+A[4];

Sun(5)=C[5]+C[4];

Sun(6)=C[6]+C[4];

Sun(7)=C[7]+C[6]+C[4];

Sun(8)=C[8];

,,,,,,

int Sum(int n) //求前n项的和.

{

int sum=0;

while(n>0)

{

sum+=C[n];

n=n-lowbit(n);

}

return sum;

}

lowbit(1)=1 lowbit(2)=2 lowbit(3)=1 lowbit(4)=4

lowbit(5)=1 lowbit(6)=2 lowbit(7)=1 lowbit(8)=8 lowbit(9)=1 lowbit(10)=2 lowbit(11)=1 lowbit(12)=4 lowbit(13)=1 lowbit(14)=2 lowbit(15)=1 lowbit(16)=16 lowbit(17)=1 lowbit(18)=2 lowbit(19)=1 lowbit(20)=4 lowbit(21)=1 lowbit(22)=2 lowbit(23)=1 lowbit(24)=8 lowbit(25)=1 lowbit(26)=2 lowbit(27)=1 lowbit(28)=4 lowbit(29)=1 lowbit(30)=2 lowbit(31)=1 lowbit(32)=32

lowbit(33)=1 lowbit(34)=2 lowbit(35)=1 lowbit(36)=4 lowbit(37)=1 lowbit(38)=2 lowbit(39)=1 lowbit(40)=8 lowbit(41)=1 lowbit(42)=2 lowbit(43)=1 lowbit(44)=4 lowbit(45)=1 lowbit(46)=2 lowbit(47)=1 lowbit(48)=16 lowbit(49)=1 lowbit(50)=2 lowbit(51)=1 lowbit(52)=4 lowbit(53)=1 lowbit(54)=2 lowbit(55)=1 lowbit(56)=8 lowbit(57)=1 lowbit(58)=2 lowbit(59)=1 lowbit(60)=4 lowbit(61)=1 lowbit(62)=2 lowbit(63)=1 lowbit(64)=64

二、树状数组可以扩充到二维。

问题:一个由数字构成的大矩阵,能进行两种操作

1) 对矩阵里的某个数加上一个整数(可正可负)

2) 查询某个子矩阵里所有数字的和,要求对每次查询,输出结果。

一维树状数组很容易扩展到二维,在二维情况下:数组A[][]的树状数组定义为:

C[x][y] = ∑ a[i][j], 其中,

x-lowbit(x) + 1 <= i <= x,

y-lowbit(y) + 1 <= j <= y.

例:举个例子来看看C[][]的组成。

设原始二维数组为:

A[][]={{a11,a12,a13,a14,a15,a16,a17,a18,a19},

{a21,a22,a23,a24,a25,a26,a27,a28,a29},

{a31,a32,a33,a34,a35,a36,a37,a38,a39},

{a41,a42,a43,a44,a45,a46,a47,a48,a49}};

那么它对应的二维树状数组C[][]呢?

记:

B[1]={a11,a11+a12,a13,a11+a12+a13+a14,a15,a15+a16,...} 这是第一行的一维树状数组

B[2]={a21,a21+a22,a23,a21+a22+a23+a24,a25,a25+a26,...} 这是第二行的一维树状数组

B[3]={a31,a31+a32,a33,a31+a32+a33+a34,a35,a35+a36,...} 这是第三行的一维树状数组

B[4]={a41,a41+a42,a43,a41+a42+a43+a44,a45,a45+a46,...} 这是第四行的一维树状数组

那么:

C[1][1]=a11,C[1][2]=a11+a12,C[1][3]=a13,C[1][4]=a11+a12+a13+a14,c[1][5]=a15,C[1][6]=a15+a1 6,...

这是A[][]第一行的一维树状数组

C[2][1]=a11+a21,C[2][2]=a11+a12+a21+a22,C[2][3]=a13+a23,C[2][4]=a11+a12+a13+a14+a21+a2 2+a23+a24,

C[2][5]=a15+a25,C[2][6]=a15+a16+a25+a26,...

这是A[][]数组第一行与第二行相加后的树状数组

C[3][1]=a31,C[3][2]=a31+a32,C[3][3]=a33,C[3][4]=a31+a32+a33+a34,C[3][5]=a35,C[3][6]=a35+a3

6,...

这是A[][]第三行的一维树状数组

C[4][1]=a11+a21+a31+a41,C[4][2]=a11+a12+a21+a22+a31+a32+a41+a42,C[4][3]=a13+a23+a33 +a43,...

这是A[][]数组第一行+第二行+第三行+第四行后的树状数组

搞清楚了二维树状数组C[][]的规律了吗?仔细研究一下,会发现:

(1)在二维情况下,如果修改了A[i][j]=delta,则对应的二维树状数组更新函数为:

private void Modify(int i, int j, int delta){

A[i][j]+=delta;

for(int x = i; x< A.length; x += lowbit(x))

for(int y = j; y

C[x][y] += delta;

}

}

(2)在二维情况下,求子矩阵元素之和∑ a[i][j](前i行和前j列)的函数为

int Sum(int i, int j){

int result = 0;

for(int x = i; x > 0; x -= lowbit(x)) {

for(int y = j; y > 0; y -= lowbit(y)) {

result += C[x][y];

}

}

return result;

}

比如:

Sun(1,1)=C[1][1]; Sun(1,2)=C[1][2]; Sun(1,3)=C[1][3]+C[1][2];... Sun(2,1)=C[2][1]; Sun(2,2)=C[2][2]; Sun(2,3)=C[2][3]+C[2][2];... Sun(3,1)=C[3][1]+C[2][1]; Sun(3,2)=C[3][2]+C[2][2];

例:测试一下:

import java.util.Arrays;

public class Test{

int[][] A;//原二维数组

int[][] C;//对应的二维树状数组

public Test(){

A=new int[5][6];

C=new int[5][6];

for(int i=1;i<5;i++)

for(int j=1;j<6;j++)

Modify(i,j,1);//给A[][]每个元素加1

for(int i=1;i<5;i++){

for(int j=1;j<6;j++)

System.out.print(A[i][j]+" ");//输出A[][] System.out.println();

}

System.out.println(Sum(3,4));//求子二维数组的和 Modify(2,3,4);//将A[2][3]加4

System.out.println(Sum(3,4));//显示修改后的和

}

private int lowbit(int t){

return t&(-t);

}

int Sum(int i, int j){

int result = 0;

for(int x = i; x > 0; x -= lowbit(x)) {

for(int y = j; y > 0; y -= lowbit(y)) {

result += C[x][y];

}

}

return result;

}

private void Modify(int i, int j, int delta){

A[i][j]+=delta;

for(int x = i; x< A.length; x += lowbit(x))

for(int y = j; y

}

}

public static void main(String args[]){ Test t=new Test();

}

}

C:\java>java Test

1 1 1 1 1

1 1 1 1 1

1 1 1 1 1

1 1 1 1 1

12

16

JAVA一维数组二维数组运用的例子

题目:定义一个一维数组存储10个学生名字;定义一个二维数组存储这10个学生的6门课(C程序设计、物理、英语、高数、体育、政治)的成绩; 程序应具有下列功能: (1)按名字查询某位同学成绩 (2)查询某个科目不及格的人数,及学生名单 代码如下: import java.util.*; public class Test{ public static void main(String[]args){ Scanner input=new Scanner(System.in); String[]name={"a","b","c","d","e","f","g","h","i","l"};//存储学生的名字 int[][] grade={{50,60,70,80,90,10},{40,90,80,60,40,70},{60,80,70,60,40,90},{50,60,70,80,90,10}, {60,80,70,60,40,90},{60,70,80,90,70,70},{60,80,70,60,40,90},{60,80,70,60,40,90},{70, 80,90,70,70,70},{60,80,70,60,40,90}};//存储学生各科成绩 System.out.println("输入要查询成绩的学生名字:"); String chioce=input.nextLine(); for(int i=0;i<10;i++) { if(name[i].equals(chioce)) {System.out.println("学生:"+name[i]+"的成绩如下:"); System.out.println("C程序设计:"+grade[i][0]+"物理:"+grade[i][1]+"英 语:"+grade[i][2]+"高数:"+grade[i][3]+"体育:"+grade[i][4]+"政治:"+grade[i][5]+"\n"); break;} } System.out.println("******************************************************");

数组及其应用(详细教案)

提问:给一组数排序,这组数该如何存 放呢? 8 2 9 4 5 6 3 7 1 6 这就是本节课要解决的问题。 ?一个班学生的学习成绩 ?一行文字 ?一个矩阵 这些数据的特点是: 1.具有相同的数据类型 2.使用过程中需要保留原始数据 C语言为这些数据,提供了一种型:数组。所谓数组就是一组具有相数据的有序集合。 提出学习要求: 1 一维数组的定义和应用

2 二维数组的定义和应用 3 字符数组的应用 第七章数组 7.1一维数组及应用 7.1.1一维数组的定义方式 在C语言中使用数组必须先定义、后使用,定义数组也就确定了数组的首地址、数组元素的类型和个数(数组长度)。 一维数组的定义方式为: 类型说明符数组名[常量表达式]; 例如: 1) int a[5]; 说明整型数组a,a是数组名,有5个元素。但

是其下标从0开始计算。因此5个元素分别为a[0],a[1],a[2],a[3],a[4]。注意不能使用数组元素a[5]。 float b[10],c[20]; 说明实型数组b,b是数组名,有10个元素,实型数组c,有20个元素。 char ch[20]; 说明字符数组ch,有20个元素。 对于数组类型说明应注意以下几点:2) 数组的类型实际上是指数组元素的取值类型。对于同一个数组,其所有元素的数据类型都是相同的。 3) 数组名的书写规则应符合标识符的书写规定。 4) 数组名不能与其它变量名相同。 例如:

main() { int a; /*a为整型变量*/ float a[10]; /* 数组名a与上面的变量名a相同,错误!*/ …… } 是错误的。 5) 不能在方括号中用变量来表示元素的个数,但是可以是符号常数或常量表达式。 例如: #define FD 5 /* FD是符号常数*/ main() {

thinkphp将二维数组转换为一维数组

thinkphp将二维数组变为标签适用的一维数组 2012-01-10 11:23:31| 分类:默认分类|字号订阅 方法一: $projectList=arr1tag($projectList,array('','请选择'),'project_name'); //其中$list为传值过来的二维数组,$default为默认值,$k为指定的表字段function arr1tag($list,$default='',$k=''){ $tmp=''; if(array($list)){ if(array($default)){ $tmp[$default[0]]=$default[1]; } foreach ($list as $k1=>$v1){ $tmp[$k1+1]=$v1[$k]; } } return $tmp; } 方法二: $projectList=arr2tag($projectList,array('','请选择'),''); //根据数组下标获取对应值 function array_index2val($array,$index=0){ $value=''; if(is_array($array)){ $i=0; foreach($array as $val){

if($i===$index){ $value=$val; break; } $i++; } } return $value; } //把数据库中调出的数组转换成可以使用模版标签的数组,其中$default为默认值,$k为指定的表字段 function arr2tag($arr,$default=NULL,$K=NULL){ $tmp=''; if(is_array($arr)){ if(is_array($default)){ $tmp[$default[0]]=$default[1]; if($type==1){ $tmp[$default[2]]=$default[3]; } } foreach ($arr as $key=>$val){ if(is_array($K)){ $tmp[$val[$K[0]]]=$val[$K[1]]; }else{ $tmp[array_index2val($val,0)]=array_index2val($val,1); } } } return $tmp; } 方法三: 将读取数据库的内容直接转换为一维数组,该方法大多用于select标签 $this->where($where)->getField('id,name'); 得出的内容为 array(

树状数组及其应用

树状数组及其应用 ( Binary Indexed Trees ) 一、什么是树状数组 【引例】 假设有一列数{A i}(1<=i<=n),支持如下两种操作: 1.将A k的值加D。(k,D是输入的数) 2.输出A s+A s+1+…+A t(s,t都是输入的数,s<=t) 分析一:线段树 建立一颗线段树(线段长度1~n)。一开始所有结点的count值等于0。 对于操作1,如果把A k的值加D,则把所有覆盖了A k的线段的count值加D。只有log2n 条线段会受到影响,因此时间复杂度是O(log2n)。 每条线段[x..y]的count值实际上就是A x+A x+1+…+A y的值。 对于操作2,实际上就是把[s..t]这条线段分解成为线段树中的结点线段,然后把所有的结点线段的count值相加。该操作(ADD操作)在上一讲线段树中已介绍。时间复杂度为O (log2n)。 分析二:树状数组 树状数组是一种特殊的数据结构,这种数据结构的时空复杂度和线段树相似,但是它的系数要小得多。 增加数组C,其中C[i]=a[i-2^k+1]+……+a[i](k为i在二进制形式下末尾0的个数)。由c数组的定义可以得出:

为了对树状数组有个形象的认识,我们先看下面这张图。 如图所示,红色矩形表示的数组C[]就是树状数组。我们也不难发现,这个k就是该节点在树中的高度,因而这个树的高度不会超过logn。 【操作1】修改A[i]的值。可以从C[i]往根节点一路上溯,调整这条路上的所有C[]即可,这个操作的复杂度在最坏情况下就是树的高度即O(logn)。 定理1:若a[k]所牵动的序列为C[p1],C[p2]……C[p m],则p1=k,而p i+1=p i+2li (l i为p i在二进制中末尾0的个数)。 例如a[1]……a[8]中,a[3] 添加x; p1=k=3 p2=3+20=4 p3=4+22=8 p4=8+23=16>8 由此得出,c[3]、c[4]、c[8]亦应该添加x。 定理的证明如下: 【引理】 若a[k]所牵动的序列为C[p1],C[p2] ……C[p m],且p1

vb中一维二维数组应用

一维数组 排序 一、选择排序法: 数据已经放在一维数组中,要求从小到大排序。 数组 20 4 36 …… 45 109 3 下标 1 2 3 …… n-2 n-1 n 排序过程: 1、从第1项到第n项选择最小值,然后将第1项与最小项交换。 2、从第2项到第n项选择最小值,然后将第2项与最小项交换。 3、…… 4、从第n-1项到第n项选择最小值,然后将第n-1项与最小项交换。注意:最小值及下标由临时变量存储。 所以,需要两层循环:外层循环i执行n-1次,内层循环j执行n-i-1次For i=1 to n-1

最小值及下标由临时变量存储 tmpVal=第i项值 tmpId=第i项下标 For j=i+1 to n 若tmpVal >第j项值,则: tmpVal=第j项值 tmpId=第j项下标 next 将第i项与最小项交换 Next 从大到小呢? 二、冒泡排序法: 数据已经放在一维数组中,要求从小到大排序。 数组 20 4 36 …… 45 109 3 下标 1 2 3 …… n-2 n-1 n

两种方法:小数上浮和大数下沉。 小数上浮排序过程:从第n项到第k项,依次相临两项比较,若第m项小于第m-1项,则两项交换。(k从2到n) 第1次执行:结果是第1项至第n项中的最小值放到第1项中 1、若第n项小于第n-1项,将第n项与第n-1项交换。 2、若第n-1项小于第n-2项,将第n-1项与第n-2项交换。 3、…… 4、若第2项小于第1项,将第2项与第1项交换。 第2次执行:结果是第2项至第n项中的最小值放到第2项中 1、若第n项小于第n-1项,将第n项与第n-1项交换。 2、若第n-1项小于第n-2项,将第n-1项与第n-2项交换。 3、…… 4、若第3项小于第2项,将第3项与第2项交换。 …… 第n-1次执行: 1、若第n项小于第n-1项,将第n项与第n-1项交换。 所以,需要两层循环:外层循环i执行n-1次,内层循环j执行n-i次 For i=1 to n-1 For j=n to i+1 step -1 若第j项值<第j-1项值,则:

数据结构总结

转载自South_wind的专栏 常见的数据结构运用总结 考虑到Obsidian三个成员的擅长领域,这段时间都在做杂题,算是学习各种算法吧,趁现在休息的时间,而且大家马上要备战今年的比赛了,写写自己专攻方面的一些心得吧 扯开线段树、平衡树这些中高级的东西,先说说基础的数据结构 栈 算是代码量最小的数据结构?出栈进栈都只有一句话而已 常见用途: 消去一个序列中的相同元素(做法大家应该都知道了吧,见过很多次了) 维护一个单调的序列(所谓的单调栈,dp的决策单调?) 表达式求值(经典的栈运用,如果使用的很熟悉的话,可以处理一元、二元运算,不过最近没见过类似的题目了) 用于辅助其他算法(计算几何中的求凸包) 队列 队列应该还是很常见的数据结构了,如果专攻图论的话,spfa应该是写烂了的 这里说到的队列,是狭义的普通的队列和循环队列,不包括后面讲的一些变形 注意循环队列的写法,尽量不要使用取模运算,不然的话,遇到不厚道的出题者,可以把取模的循环队列卡到死 常见用途: 主要用于辅助其他算法,比如说spfa,bfs等(建议习惯用stl的孩子手写queue,毕竟就几行代码而已,偷懒会付出代价的。。。) 双端队列 如果写dp写的多的话,这个东西应该还是算是比较基础的东西了,双端队列多用于维护一个满足单调性的队列 还是建议手写,stl的deque使用块状链表写的,那东西的复杂度是O(Nsqrt(N))的,不要被迷惑了。 常见用途: dp的单调性优化,包括单调队列优化和斜率优化,都要用到这个结构 计算几何中的算法优化,比如半平面交 树的分治问题中利用单调队列减少转移复杂度 链表Dancing Links 写图论的不要告诉我不会写这货,链表可以写单双向,循环非循环的,高级点儿的可以考虑十字链表,麻花链表 不过链表可以说是树形结构的基础,如果这个掌握的不好,那么树形结构写起来就会很纠结 链表的优势在于可以O(1)的插入删除,如果要求插入的位置只是在序列的两端的话,这个数据结构是最方便的了(无视双端队列) hash表就是用链表实现的,熟悉hash的同学可以试试看怎么使你的hash效率提高

树状数组

树状数组 武钢三中 吴豪【引言】 在解题过程中,我们有时需要维护一个数组的前缀和S[i]=A[1]+A[2]+...+A[i]。但是不难发现,如果我们修改了任意一个A[i],S[i]、S[i+1]...S[n]都会发生变化。可以说,每次修改A[i]后,调整前缀和S[]在最坏情况下会需要O(n)的时间。当n非常大时,程序会运行得非常缓慢。因此,这里我们引入“树状数组”,它的修改与求和都是O(logn)的,效率非常高。 【理论】 为了对树状数组有个形 象的认识,我们先看下面这张图。 如图所示,红色矩形表示的数组C[]就是树状数组。 这里,C[i]表示A[i-2^k+1]到A[i]的和,而k则是i在二进制时末尾0的个数,或者说是i用 2的幂方和表示时的最小指数。( 当然,利用位运算,我们可以直接计算出2^k=i&(i^(i-1)) )同时,我们也不难发现,这个k就是该节点在树中的高度,因而这个树的高度不会超过logn。所以,当我们修 改A[i]的值时,可以从C[i]往根节点一路上溯,调整这条路上的所有C[]即可,这个操作的复杂度在最坏情况下就是树的高度即O(logn)。另外,对于求数列的前n项和,只需找到n以前的所有最大子树,把其根节点的C加起来即可。不难发现,这些子树的数目是n在二进制时1的个数,或者说是把n展开 成2的幂方和时的项数,因此,求和操作的复杂度也是O(logn)。 接着,我们考察这两种操作下标变化的规律: 首先看修改操作: 已知下标i,求其父节点的下标。我们可以考虑对树从逻辑上转化:

如图,我们将子树向右对称翻折,虚拟出一些空白结点(图中白色),将原树转化成完全二叉树。 有图可知,对于节点i,其父节点的下标与翻折出的空白节点下标相同。 因而父节点下标 p=i+2^k (2^k是i用2的幂方和展开式中的最小幂,即i为根节点子树的规模)即 p = i + i&(i^(i-1)) 。 接着对于求和操作: 因为每棵子树覆盖的范围都是2的幂,所以我们要求子树i的前一棵树,只需让i减去2的最小幂即可。即 p = i - i&(i^(i-1)) 。 至此,我们已经比较详细的分析了树状数组的复杂度和原理。 在最后,我们将给出一些树状数组的实现代码,希望读者能够仔细体会其中的细节。 【代码】 求最小幂2^k: in t L o wb i t(in t t) { retur n t & ( t ^ ( t - 1 ) ); } 求前n项和: in t S um(in t e n d) { in t sum = 0; wh il e(e n d> 0) {

1701 【树状数组】数星星(POJ2352 star) 1702 【树状数组】矩阵(POJ 2155)

【树状数组】数星星(POJ2352 star) Time Limit:1000MS Memory Limit:65536K Total Submit:23 Accepted:16 Description 天文学家经常观察星象图。星象图中用平面上的点来表示一颗星星,每一颗星星都有一个笛卡尔坐标。设定星星的等级为其左下角星星的总数。天文学家们想知道星星等级的分布情况。 比如上图,5号星星的等级为3(其左下角有编号为1、2、4的星星共三颗)。2号星星和4号星星的等级为1。在上图中只有一颗星星等级为0,两颗星星等级为1,一颗星星等级为2,一颗星星等级为3。 给定一个星象图,请你写一个程序计算各个等级的星星数目。 Input 输入的第一行包含星星的总数N (1<=N<=15000)。接下来N行,描述星星的坐标(X,Y)(X和Y用空格分开,0<=X,Y<=32000)。星象图中的每个点处最多只有一颗星星。所有星星按Y坐标升序排列。Y坐标相等的星星按X坐标升序排列。 Output 输出包含N行,每行一个整数。第一行包含等级0的星星数目,第二行包含等级1的星星数目,依此类推,最后一行包含等级为N-1的星星数目。 Sample Input 5

1 1 5 1 7 1 3 3 5 5 Sample Output 1 2 1 1

?const maxn=60000; ?var i,n,x,y,k:longint; ?a:array[0..15000] of longint; ?c,stars:array[0..60000] of longint; ?procedure add(p,d:longint); ?begin ? while p<=maxn do begin ? c[p]:=c[p]+d; ? p:=p+p and (-p); ? end; ?end; ?function sum(p:longint):longint; ?var res:longint; ?begin ? res:=0; ? while p>0 do begin ? res:=res+c[p]; p:=p-p and (-p); ? end; ? exit(res); ?end; ?begin ?readln(n); ?for i:=1 to n do begin ? readln(x,y); ? add(x+1,1); ? k:=sum(x+1)-1; ? stars[k]:=stars[k]+1; ?end; ?for i:=0 to n-1 do writeln(stars[i]); ?end.

华附高一入学测试说明

高一入学测试说明 一、命题指导思想 符合选拔性测试的规律和要求,反映各测试科目初中课程标准的整体要求,部分内容可 超出初中各科教学大纲,以有利于选拔具有学习潜能和创新精神的合格新生。 试题以能力测试为主导,在考查考生对基础知识、基本技能和方法掌握程度的同时,注 重能力和科学素养的考查,注重考查运用所学知识分析、解决具体问题的能力;强调知识之间的内在联系;注重理论联系实际。全面落实对“知识与技能”、“过程与方法”、“情感态度与 价值观”三维目标的考查。 二、测试范围内容和测试能力要求 语文测试说明 主题内容 测试范围 依据初中、高中课程标准,根据广东奥林匹克学校对高一奥班新生 文化素质的要求,结合奥校初中、高中语文教学实际,确定语文科测 试内容。 考查内容主要分为“语言文字运用”、“古代诗文阅读”、“现代 文阅读”和“写作”四大板块。 一、语言文字运用 正确、熟练、有效地运用语言文字。 1.识记 (1)识记现代汉语普通话常用字的字音 (2)识记并正确书写现代常用规范汉字 2.表达应用 (1) 正确使用词语(包括熟语) (2) 辨析并修改病句 (3) 扩展语句,压缩语段 (4) 正确运用常见的修辞手法 (5) 语言表达简明、连贯、得体、准确 二、古代诗文阅读 阅读浅易的古代诗文。 1.识记常见的名句名篇。 2.理解 (1)理解常见的文言实词和虚词 (2)翻译文中的句子 3.分析综合 (1)筛选文中的信息 (2)归纳内容要点,概括中心意思 三、现代文阅读 (一)文学类文本阅读 阅读鉴赏中外文学作品。 2 / 7 1、整体把握文学作品的内容、情感、形象

2、理清作者思路和作品线索 3、揣摩作品中的精彩细节 4、品味语言,领悟内涵 5、鉴赏作品的写作技巧和艺术特色 6、探索作品蕴涵的民族心理和人文精神 (二)实用类文本阅读 1、整体把握实用类文本的主要内容 2、阅读科技、社科、新闻作品,筛选信息,概括要点 3、运用文中知识对相关实际问题进行分析推断 4、阅读论述类文章,理解观点与材料之间的联系 5、联系实际,对文中的观点作出自己的判断 6、体会和分析实用类文本的语言特点 四、写作 能熟练写作记叙文,会写简单的论述类、实用类等文章。 能力要求考查考生识记、理解、分析综合、鉴赏评价、表达应用和探究六种能力,其中阅读理解、分析归纳和写作能力是考查的重点。 测试题型1.选择题约25% 2.非选择题约75% 数学I 测试说明 主题内容 测试范围 命题范围为国家教育部2001 年颁布的《全日制义务教育数学课程标 准(实验稿)》、《义务教育课程标准实验教科书——数学(七、八、 九年级)》(人民教育出版社)所规定的内容。主要包括: (1)实数及其运算 (2)整式、分式、二次根式的概念与运算 (3)一元一次方程、一元二次方程、方程组 (4)一元一次不等式、一元一次不等式组 (5)一次函数、反比例函数、二次函数的性质及其图象 (6)三角形、四边形、多边形、圆及相应图形的性质 (7)平移、对称、旋转、相似等图形变换的性质 (8)概率、统计中的概念与运算 3 / 7 (9)以上内容在实际问题中的应用 能力要求 主要考查五种数学能力和四种思想方法,即: (1)空间想象能力、抽象概括能力、推理论证能力、运算求解能力、数 据处理能力 (2)等价转换思想、函数与方程思想、数形结合思想、分类讨论思想 测试题型 (1)选择题,共6 道 (2)填空题,共6 道 (3)解答题,共4 道

树状数组求区间和的一些常见模型

树状数组求区间和的一些常见模型 树状数组在区间求和问题上有大用,其三种复杂度都比线段树要低很多……有关区间求和的问题主要有以下三个模型(以下设A[1..N]为一个长为N的序列,初始值为全0): (1)“改点求段”型,即对于序列A有以下操作: 【1】修改操作:将A[x]的值加上c; 【2】求和操作:求此时A[l..r]的和。 这是最容易的模型,不需要任何辅助数组。树状数组中从x开始不断减lowbit(x)(即x&(-x))可以得到整个[1..x]的和,而从x开始不断加lowbit(x)则可以得到x 的所有前趋。代码: void ADD(int x, int c) { for (int i=x; i<=n; i+=i&(-i)) a[i] += c; } int SUM(int x) { int s = 0; for (int i=x; i>0; i-=i&(-i)) s += a[i]; return s; } 操作【1】:ADD(x, c); 操作【2】:SUM(r)-SUM(l-1)。 (2)“改段求点”型,即对于序列A有以下操作: 【1】修改操作:将A[l..r]之间的全部元素值加上c; 【2】求和操作:求此时A[x]的值。 这个模型中需要设置一个辅助数组B:B[i]表示A[1..i]到目前为止共被整体加了多少(或者可以说成,到目前为止的所有ADD(i, c)操作中c的总和)。 则可以发现,对于之前的所有ADD(x, c)操作,当且仅当x>=i时,该操作会对A[i]

的值造成影响(将A[i]加上c),又由于初始A[i]=0,所以有A[i] = B[i..N]之和!而ADD(i, c)(将A[1..i]整体加上c),将B[i]加上c即可——只要对B数组进行操作就行了。 这样就把该模型转化成了“改点求段”型,只是有一点不同的是,SUM(x)不是求B[1..x]的和而是求B[x..N]的和,此时只需把ADD和SUM中的增减次序对调即可(模型1中是ADD加SUM减,这里是ADD减SUM加)。代码: void ADD(int x, int c) { for (int i=x; i>0; i-=i&(-i)) b[i] += c; } int SUM(int x) { int s = 0; for (int i=x; i<=n; i+=i&(-i)) s += b[i]; return s; } 操作【1】:ADD(l-1, -c); ADD(r, c); 操作【2】:SUM(x)。 (3)“改段求段”型,即对于序列A有以下操作: 【1】修改操作:将A[l..r]之间的全部元素值加上c; 【2】求和操作:求此时A[l..r]的和。 这是最复杂的模型,需要两个辅助数组:B[i]表示A[1..i]到目前为止共被整体加了多少(和模型2中的一样),C[i]表示A[1..i]到目前为止共被整体加了多少的总和(或者说,C[i]=B[i]*i)。 对于ADD(x, c),只要将B[x]加上c,同时C[x]加上c*x即可(根据C[x]和B[x]间的关系可得); 而ADD(x, c)操作是这样影响A[1..i]的和的:若x=i)会将A[1..i]的和加上i*c。也就是,A[1..i]之和= B[i..N]之和* i + C[1..i-1]之和。 这样对于B和C两个数组而言就变成了“改点求段”(不过B是求后缀和而C是求前缀和)。 另外,该模型中需要特别注意越界问题,即x=0时不能执行SUM_B操作和ADD_C 操作!代码: void ADD_B(int x, int c) {

信息学奥林匹克教程(数据结构篇)

《信息学奥林匹克教程(数据结构篇) 奥赛经典高级教程系列(奥赛经典高级教程系列)》 内容简介 为了进一步推广、普及计算机技术,提高竞赛水平,在原来编写的一套《信息学奥林匹克教程》(基础篇·提高篇·语言篇)的基础了,我们又编写了这本《数据结构篇》。 《数据结构篇》主要帮助学生全面地掌握数据结构知识与应用技巧,相对于其他数据结构书不同之处就在于增加了一些针对性的例题和习题,着眼点是提高数据结构的应用方法与技巧,是一本具有实战意义的教材。 从逻辑角度看,数据可归结为三种基本结构:线性结构、树结构和图结构;从存储角度看,数据可归结为四种基本结构:顺序结构、链接结构、索引结构和散列结构。每一种逻辑结构可根据不同需要采用不同的存储结构,或者不同的存储结构的组合。数据的逻辑结构和存储结构确定后,再结合指定运算的算法,就容易利用一种程序设计语言编写出程序。通过数据结构的学习,能够大大提高程序设计能力和水平。 《数据结构篇》是为广大信息学爱好者学习数据结构而精心编著的一本教材。本书内容比较全面,着重于实用与实战,在算法分析上简明扼要,细致清晰,便于自学。全书共分十章:第一章为概论,它为学习以后的各章做准备;第二章至第五章为线性结构;第六章和第七章分别为树结构和图结构,分别讨论了每一种逻辑结构所对应的存储结构和相应的算法;第八章和第九章分别为查找与排序,它包含了数据处理中主要使用的几种查找和内排序方法;最后一章为读者提供了检测知识的模拟试题及解答。 作者简介 向期中,长郡中学特级教师,湖南省计算机学会理事,国际金牌教练,国家教育部计算机课程咨询委员会委员。对中小学计算机教育事业有一种执着的追求,参加工作20年来,一直以“当一流教师,办一流教育,出一流人才”为自己的工作目标,对中小学计算机教学和青少年信息学奥林匹克竞赛的辅导倾注了全部热情和心血。在信息学奥林匹克竞赛培训中把“先做人,后成才”的育人理念贯穿到整个奥赛培训的始终,学生在愉快的学习中取得了一个个辉煌的成绩:在近几年的信息学奥林匹克竞赛中,辅导的学生有100多人获湖南省一等奖,11人次进入国家集训队,3人进入国家代表队,3人获国际金牌。撰写了《信息学(计算机)国际奥林匹克Turbo Pas—cal 6.0》等十多部信息学专著。多次荣获园丁奖和全国优秀辅导员称号,还先后获得全国中小学计算机教育先进工作者、湖南省优秀教师和全国信息学奥林匹克竞赛高级指导教师等荣誉称号。

线段树

线段树 目录 定义 基本结构 实现代码 树状数组 编辑本段定义 区间在[1,5]内的线段树 线段树又称区间树,是一种对动态集合进行维护的二叉搜索树,该集合中的每个元素 x 都包含一个区间 Interval [ x ]。 线段树支持下列操作: Insert(t,x):将包含区间 int 的元素 x 插入到树中; Delete(t,x):从线段树 t 中删除元素 x; Search(t,i):返回一个指向树 t 中元素 x 的指针。 编辑本段基本结构 线段树是建立在线段的基础上,每个结点都代表了一条线段[a , b]。长度为1的线段称为元线段。非元线段都有两个子结点,左结点代表的线段为[a , (a + b ) / 2],右结点代表的线段为[( a + b ) / 2 , b]。 右图就是一棵长度范围为[1 , 5]的线段树。 长度范围为[1 , L] 的一棵线段树的深度为log ( L - 1 ) + 1。这个显然,而且存储一棵线段树的空间复杂度为O(L)。 线段树支持最基本的操作为插入和删除一条线段。下面以插入为例,详细叙述,删除类似。 将一条线段[a , b] 插入到代表线段[l , r]的结点p中,如果p不是元线段,那么令mid=(l+r)/2。如果bmid,那么将线段[a , b] 也插入到p的右儿子结点中。

插入(删除)操作的时间复杂度为O (Log N)。 上面的都是些基本的线段树结构,但只有这些并不能做什么,就好比一个程序有输入没输出,根本没有任何用处。 最简单的应用就是记录线段有否被覆盖,并随时查询当前被覆盖线段的总长度。那么此时可以在结点结构中加入一个变量int count;代表当前结点代表的子树中被覆盖的线段长度和。这样就要在插入(删除)当中维护这个count值,于是当前的覆盖总值就是根节点的count值了。 另外也可以将count换成bool cover;支持查找一个结点或线段是否被覆盖。[1] 相信对算法设计或者数据结构有一定了解的人对线段树都不会太陌生。它是能够在log(MaxLen)时间内完成线段的添加、删除、查询等操作。但一般的实现都有点复杂而线段树应用中有一种是专门针对点的。(点树?)它的实现却非常简单。 这种数据结构有什么用?我们先来考虑一下下面的需求(全部要求在LogN 时间内完成):如何知道一个点在一个点集里的大小“排名”?很简单,开一个点数组,排个序,再二分查找就行了;如何在一个点集内动态增删点?也很简单,弄个平衡树就行了(本来平衡树比线段树复杂得多,但自从世界上有了STL set 这么个好东东,就……^_^)那如果我既要动态增删点,也要随时查询到一个点的排名呢?那对不起,可能就要出动到我们的“点树”了。 其实现原理很简单:每当增加(或删除)一个大小为X的点时,就在树上添加(或删除)一条(X,MaxLen)的线段(不含端点),当要查询一个点的排名时,只要看看其上有多少条线段就可以了。针对这一需求,这里有个非常简单的实现(见以下代码,十多行,够短了吧?)其中clear()用于清空点集;add()用于添加一个点;cntLs()返回小于n的点的个数,也就是n的升序排名,类似地cntGt 是降序排名。 这个点树有什么用呢?其中一个应用时在O(NlogN)时间内求出一个排列的逆序数(https://www.360docs.net/doc/9e16501403.html,/show_problem.php?pid=1484,你有更好的算法吗?欢迎交流)方法是每读到一个数x,就让逆序数+=cntGt(x);然后再 add(x)。 这个实现还可以进行一些扩展。比如删除del(int n),只要把add(int n)中的++size换成--size,把a[i/2]++改成a[i/2]--即可。另外还可以通过二分查找功能在O(logN)时间内查到排名第n的点的大小。应该也可以三四行内搞定。 补充:杨弋同学在2008年信息学奥赛冬令营上新发明了一种线段树的省空间堆式存储法,具体方法可以见08年冬令营课件. 编辑本段实现代码 template < int N > // 表示可用区间为[0,N),其中N必须是2的幂数; class PointTree { int a[ 2 * N]; int size; void clear() { memset( this , 0 , sizeof ( * this ));} void add( int n) {

C语言程序设计 一维数组

5.1一维数组 5.1.1找最小数 【例5-1】输入10个整数,找出其中的最小数,然后输出这10个数和最小数。 参考程序如下: /*程序5-1.c*/ #include int main() { int i,min,a[10];/*定义数组*/ printf("Enter data:");/*提示输入*/ for(i=0;i<10;i++) scanf("%d",&a[i]);/*输入10个数*/ min=a[0];/*假设下标为0的元素最小*/ for(i=1;i<10;i++)/*找最小值a[i]*/ if(a[i]

Vijos 1448校门外的树(树状数组与线段树)

Vijos 1448校门外的树 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有可以吃掉补充体力的…… 如今学校决定在某个时刻在某一段种上一种树,保证任一时刻不会出现两段相同种类的树,现有两个操作: K=1,读入l,r表示在l~r之间种上的一种树 K=2,读入l,r表示询问l~r之间能见到多少种树 (l,r>0) 输入第一行n,m表示道路总长为n,共有m个操作 接下来m行为m个操作 输出对于每个k=2输出一个答案 样例输入 5 4 1 1 3 2 2 5 1 2 4 2 3 5 样例输出 1 2 括号序列+树状数组 什么是括号序列下面简单介绍一下(感谢tiger教会我) 假设有一个长度是20的数轴,现在我们要在2 15之间种上一种树,那么我们可以在2处添加一个‘(’,在15的地方添加一个‘)’,这就是简单的括号序列。 如果要统计某个区间树的种类,例如3 10,我们只需要统计10之前(包括10)有多少个‘(’,统计3之前有多少个‘)’,(不包括3)。 这样光说可能很难理解,下面给一个实例。 左括号和右括号表示的是在这些区间内种上了树。(日,感觉有点像在画大便)

假设这时候需要统计的是 5 10之间有多少种树,那么,只要在10之前种的树都是有效的(这时候先不管5的限制),也就是统计左括号的个数,一共是6个,下面加上5个限制,也就是说,在5之前,我们统计一下有多少右括号,也就是能与左括号匹配掉的括号有多少个?换句话说,就是有多少种树被限制了(自己意会下把,实在是用文字说不出来); 把程序也拿出来晒晒把(脑残的vijos,用writeln6个点超时,用write过了,还9ms) program vijos; var c1,c2:array[0..50000]of longint; n,m:longint; function lowbit(x:longint):longint; begin lowbit:=x and (x xor (x-1)); end; procedure addl(i:longint); begin while i<=n do begin inc(c1[i]); inc(i,lowbit(i)); end; end; procedure addr(i:longint); begin while i<=n do begin inc(c2[i]); inc(i,lowbit(i)); end; end; function findl(i:longint):longint; begin findl:=0; while i>0 do

数组的综合应用例子

数组的综合应用例子 时间:2009-6-19 8:54:45 点击:1409 数组的综合应用 为了加深对数组的理解,下面结合一些常用算法的编程来更加深入地学习和使用数组。由于一维数组和二维数组是程序设计中最常用的数组形式,因此这里的举例均为一维和二维数组。 1.数组元素的输入和输出 [例5-12] 由用户输入5个数组元素的值并把它们输出在窗体上。 Option Explicit Private Sub Command1_Click() Dim a(1 To 5) As Integer, i As Integer For i=1 To 5 a(i)=InputBox("请输入第" & Str(i) & "个元素") Next For i=1 To 5 Print "a (";i; ")="; a(i) Next End Sub 程序运行后,单击命令按钮,执行事件过程Command1_Click。若输入5个值10,20,30,40,50,则窗体上显示的输出结果是: a(1)=10 a(2)=20 a(3)=30 a(4)=40 a(5)=50 程序中声明了一个具有5个元素的一维整型数组,分别用循环语句输入、输出数组元素的值。在循环体内,数组元素用循环控制变量i作下标,i值的不同就表示数组元素的不同。在程序中引用数组元素时,其下标可以使用表达式。只要表达式的结果不超出数组定义的上界和下界范围,下标表达式就是合法的。例如本例中,若i=2,则: a(i+1)的值为30; a(a(i+3)\10)的值为50。 下标表达式的值还可以是实数,此时VB将自动对其进行四舍五入取整。例如: a(1+0.4)的值是10; a(2+0.5)的值30。 2.数组元素插入删除

一维数组教案

“一维数组”教学方案 【课题】一维数组 【学时】50分钟 【授课学生分析】 教学对象为大学本科学生,通过前面程序的基本结构(顺序结构、选择结构、循环结构)的学习,学生已具备一定的编程能力,为学习数组的应用打下了基础。【教学目标】 1、知识目标 理解数组的概念,掌握对数组的定义、初始化、引用的应用。 2、能力目标 通过对数组定义、引用的掌握,引导学生利用数组解决同类型的多变量的问题,培养和提高学生逻辑思维能力,提高动手编程能力。 3、情感目标 利用上机分组操作,培养学生的协作精神。激发学生学习兴趣,使学生积极参与体验成功的快乐。 【重点难点】 重点:一维数组的定义、一维数组的初始化、一维数组的引用 难点:一维数组的引用、一维数组的应用 【教学方法】 1、采用案例、情境、启发式教学法。 2、以例子讲解→练习→引发学生思考为流程;循序渐进的教学策略。 3、运用“提出问题→学生尝试→演示与交流→解决问题”的课堂教学模式。【教学策略】 基本知识采用的基本模式:提出问题→学生尝试→演示与交流→解决问题。 然后是能力拓展,学生分组从其它工作表中挑选内容完成挑战,适用于分层进行教学,最后展示与交流,使学生享有成就感,充分发挥学生的应用知识的能力。 以学生为主、教师引导并给予鼓励,充分发挥学生的主体性及积极性。

【教学过程】

【教学后记】 专业班的学生基础较好,旧知识点没有过多的强调。在整个教学过程中,紧紧围绕提出问题——分析问题——解决问题三个环节,充分体现了学生的主体地位、以及对学生各种能力的培养。 对于本次课的重点、难点,我通过启发引导、提出问题、巩固练习等形式,充分调动学生的学习积极性,使他们参与到教学的整个过程,让学生在积极思考,积极探索中掌握新知识、消化本节课的重点、难点。

数组程序举例

?一个班学生的学习成绩 ?一行文字 ?一个矩阵 这些数据的特点就是: 1、具有相同的数据类型 2、使用过程中需要保留原始数据 C语言为这些数据,提供了一种构造数据类型:数组。 所谓数组就就是一组具有相同数据类型的数据的有序集合。

一维数组及其应用 例1:一维数组元素赋值及输出练习、 main() { int i,a[10]; /* 定义数组整型数组a,它含有十个元素。*/ for(i=0;i<=9;i++) a[i]=i; /*通过for循环依次为数组a中的每个元素赋值。*/ for(i=9;i>=0;i--) /*通过for循环依次输出数组a中的每个元素的值。*/

printf("%3d ",a[i]); /*请注意输出元素的顺序*/ } 运行结果: 9 8 7 6 5 4 3 2 1 0 总结:程序使a[0]到a[9]的值为0~9,然后按逆序输出。 例2:用数组来处理求Fibonacci(菲波那契) 数列问题,求出前40个数并以每行4个数输出。 Fibonacci 数列: F1 = 1 n =1 F2 = 1 n =2 Fn = Fn-1 + Fn-2 n ≥ 3

即:1 1 2 3 5 8 13 。。。 #include main ( ) { int i; long f [40] = {1, 1}; /*定义长整型数组f存放40个Fibonacci 数,对第一个与第二个元素先赋初值1 */ for ( i = 2; i < 40; i++) /* 与得到其值*/ f [i] = f [i-2] + f [i-1]; for ( i = 0; i < 40; i++) /* 利用循环依次输出40个数*/

信息学奥赛知识结构图

SASLP ├─01.基础(base) │├─01.高精度(bignum) │├─02.排序(sort) ││├─01.选择排序(select sort) ││├─02.冒泡排序(bubble sort) ││├─03.希尔排序(shell sort) ││├─04.快速排序(quick sort) ││├─05.归并排序(merge sort) ││├─06.堆排序(heap sort) ││└─07.桶排序(bucket sort) │├─03.分治法(dichotomy) │├─04.动态规划(dynamic programming) ││├─01.单调队列(humdrum queue) ││├─02.四边形不等式() ││└─03.决策单调性() │├─05.贪心(greedy) │└─06.搜索(search) │├─01.深度优先搜索(depth first search) │├─02.宽度优先搜索(breadth first search) │└─03.迭代加深搜索(iterative deepening) ├─02.数学(maths) │├─01.高斯消元(gauss elimination) │├─02.同余(modular arithmetic) │├─03.进位制() │├─04.开方(evolution) │└─x.01.群论(group theory) ├─03.数据结构(data structure) │├─01.线性表(linear table) ││├─01.栈(stack) ││├─02.队列(queue) ││├─03.哈希表(hash array) ││└─04.链表(linked list) │├─02.优先队列(priority queue) ││├─01.堆(heap) ││└─02.单调队列(humdrum queue) │├─03.线段树(interval tree) │├─04.树状数组(tree array) │├─05.二叉查找树&平衡树(binary search tree & balanced search tree) ││├─01.二叉查找树(binary search tree) ││├─02.伸展树(splay) ││├─03.Treap(treap) ││├─04.SBT(size balanced tree)

相关文档
最新文档