软考程序员数据结构笔记Word下载.docx
《软考程序员数据结构笔记Word下载.docx》由会员分享,可在线阅读,更多相关《软考程序员数据结构笔记Word下载.docx(35页珍藏版)》请在冰豆网上搜索。
模式匹配
字符串相加
求子串
(i,j)<
=>
K
注意:
不同矩阵所用的公式不同;
稀疏矩阵的转置(两种方式,后种为妙)
和数组有关的算法
--------------------------------------------------------------------------------
例程:
求两个长整数之和。
a=13056952168
b=87081299
数组:
a[]:
1
3
0
5
6
9
2
8
b[]:
8
7
由于以上的结构不够直观(一般越是直观越容易解决)将其改为:
11 86125965031a[0]=11(位数)
8 99218078000b[0]=8
c进位 01100111100
c[]:
11 76433044231c[0]的值(C位数)由c[max_s+1]决定!
注意:
在求C前应该将C(max_s+1)位赋0.否则为随机数;
较小的整数高位赋0.
算法:
已知a,b两个长整数,结果:
c=a+b;
总共相加次数:
max_s=max(a[],b[])
程序:
for(i=1;
i<
=max_s;
i++){
k=a[i]+b[i]+c[i];
c[i]=k%10;
c[i+1]=k/10;
}
求c位数:
if(c[max_s+1]==0)
c[0]=max_s;
else
c[0]=max_s+1;
以下代码是我编的(毕竟是初学者.不太简洁大家不要见怪!
):
/*两长整数相加*/
#include<
stdio.h>
string.h>
#definePRINprintf("
"
);
intflag=0;
/*a[0]>
b[0]?
1:
0*/
/*max(a[],b[]){}*/
change(charda[],chardb[],inta[],intb[],intc[]){
inti;
if(a[0]>
b[0]){
for(i=1;
=a[0];
a[i]=da[a[0]-i]-'
0'
i++);
/*a[0]-'
sogood!
*/
=b[0];
b[i]=db[b[0]-i]-'
for(i=b[0]+1;
b[i]=0,i++);
=a[0]+1;
c[i]=0,i++);
flag=1;
}
else{
for(i=a[0]+1;
a[i]=0,i++);
=b[0]+1;
add(inta[],intb[],intc[]){
inti,sum;
if(flag==1){
sum=a[i]+b[i]+c[i];
c[i+1]=sum/10;
c[i]=sum%10;
}
if(c[a[0]+1]==0)
c[0]=a[0];
else
c[0]=a[0]+1;
if(c[b[0]+1]==0)
c[0]=b[0];
c[0]=b[0]+1;
voidprint(intm[]){
for(i=m[0];
i>
=1;
i--)
printf("
%d,"
m[i]);
PRIN
main(){
ints;
inta[20],b[20],c[20];
charda[]={"
123456789"
};
chardb[]={"
12344443"
a[0]=strlen(da);
b[0]=strlen(db);
printf("
a[0]=%d"
a[0]);
b[0]=%d"
b[0]);
change(da,db,a,b,c);
flag=%d"
flag);
-----------------"
print(a);
s=abs(a[0]-b[0]);
+"
for(s=s*2-1;
s>
0;
s--)
printf("
print(b);
for(s=s*2-1;
printf("
print(a);
print(b);
add(a,b,c);
print(c);
时间复杂度计算:
●确定基本操作
●计算基本操作次数
●选择T(n)
●lim(F(n)/T(n))=c
●0(T(n))为时间复杂度
上例子的时间复杂度为O(max_s);
--------------------------------------------------------------------------------
二:
链表
1、知识点
●逻辑次序与物理次序不一致存储方法;
●单链表的定义:
术语(头结点、头指针等)
●注意带头结点的单链表与不带头结点的单链表区别。
(程序员考试一般不考带头结点,因为稍难理解)
●插入、删除、遍历(p==NULL表明操作完成)等操作
●循环链表:
定义,存储表示,操作;
●双向链表:
定义,存储方法,操作;
单链表和循环链表区别在最后一个指针域值不同。
2、操作
●单链表:
插入X,删除X,查找X,计算结点个数
●单链表的逆置(中程曾考)
head->
NULL/p->
a1/p->
a2/p->
a3/p……an/NULL注:
p代表指针;
NULL/p代表头结点
=》head->
an/p->
an-1/p->
an-2/p……a1/NULL
●循环链表的操作:
插入X,删除X,查找X,计算结点个数;
用p=head->
next来判断一次计算结点个数完成;
程序段如下:
k=0;
do{
k++;
p=p->
next;
}while(p!
=head->
next);
●双向链表
●多项式相加
●有序链表合并
已知两个字符串S,T,求S和T的最长公子串;
1、逻辑结构:
字符串
2、存储结构:
数组
3、算法:
精化(精细化工)**老顽童注:
此处“精细化工”说明好像不对!
s="
abaabcacb"
t="
abdcabcaabcda"
当循环到s.len-1时,有两种情况:
s="
、s="
s.len-2时,有三种情况:
.
1s.len种情况
程序思路:
tag=0//没有找到
for(l=s.len;
l>
0&
&
!
tag;
l--){
判断长度为l的s中的子串是否为t的子串;
若是:
tag=1;
长度为l的s的子串在s中有(s.len-l+1)个。
子串0:
0~l-1
1:
1~l
2:
2~l+1
3:
3~l+2
……
……
s.len-l:
s.len-l~s.len-1
由上面可得:
第j个子串为j~l+j-1。
判断长度为l的s中的子串是否为t的子串:
for(j=0;
j<
S.LEN-L+1&
TAG;
J++){
判断s中长度为l的第j个子串是否为t的子串;
如果是:
模式结构:
tag=0;
tag==0;
for(j=0;
J++){
?
?
用模式匹配方法确定s[j]~s[l+j-1]这个字符串是否为t的子串;
//好好想想
若是,tag=1;
在前面笔者编了一些程序:
链表,长整型数相加,三元组表转置以及一些简单的函数.其实有些算法想想是很简单,不过写起来还是需要一定耐心和C基础的,如果你自己觉得各算法都很懂了,不妨开机编编试试.或许会有一些新的发现与体会.
栈和队列
1、知识点:
●栈的定义:
操作受限的线性表
●特点:
后进先出
●栈的存储结构:
顺序,链接
/push(s,d)
●栈的基本操作:
pop(s)
栈定义:
struct{
datatypedata[max_num];
inttop;
};
●队列定义
特点:
先进先出
/入队列in_queue(Q,x)
●队列的操作:
出队列del_queue(Q)
●队列存储结构:
链队列:
Typedefstructnode{
Datatypedata;
Structnode*next;
}NODE;
Typedefstruct{
NODE*front;
NODE*rear;
}Queue;
顺序队列:
intfront,rear;
问题:
队列ó
线性表
假溢出<
=循環队列
队列满,队列空条件一样<
=浪费一个存储空间
递归
定义:
问题规模为N的解依赖于小规模问题的解。
问题的求解通过小规模问题的解得到。
包括二个步骤:
1)递推6!
5!
4!
3!
2!
1!
0!
2)回归720<
=120<
=24<
=6<
=2<
=1<
=0
递归工作栈实现递归的机制。
2、有关算法:
1)顺序,链表结构下的出栈,入栈
2)循環,队列的入队列,出队列。
3)链队列的入队列,出队列。
4)表达式计算:
后缀表达式35+6/4368/+*-
中缀表达式(3+5)/6-4*(3+6/8)
由于中缀比较难处理,计算机内一般先将中缀转换为后缀。
运算:
碰到操作数,不运算,碰到操符,运算其前两个操作数。
中缀=>
后缀
5)迷宫问题
6)线性链表的递归算法一个链表=一个结点+一个链表
intfuction(NODE*p){
if(p==NULL)return0;
elsereturn(function(p->
next));
树与二叉树
一、知识点:
1.树的定义:
data_struct(D,R);
其中:
D中有一个根,把D和出度去掉,可以分成M个部分.
D1,D2,D3,D4,D5…DM
R1,R2,R3,R4,R5…RM
而子树Ri形成树.
1)递归定义高度
2)结点个数=1
O
--0
O
--1
O--2
此树的高度为2
2.二叉树定义:
结点个数>
=0.
3.术语:
左右孩子,双亲,子树,度,高度等概念.
4.二叉树的性质
●层次为I的二叉树I层结点2I个
●高度为H的二叉树结点2H+1-1个
●H(点)=E(边)+1
●个数为N的完全二叉树高度为|_LOG2n_|
●完全二叉树结点编号:
从上到下,从左到右.
i结点的双亲:
|_i/2_||_i-1/2_|
1
i结点的左孩子:
2i2i+1
2
3
i结点的右孩子:
2i+12i+24
5
6
7
(根)1为起点0为起点
二叉树的存储结构:
1)扩展成为完全二叉树,以一维数组存储。
A
B
C
D
E
F
G
H
I
数组下标0123456789101112
元素ABCDEFGH I
2)双亲表示法
数组下标012345678
元素ABCDEFGHI
双亲-100122334
3)双亲孩子表示法
数组下标012345…
元素ABCDEF…
双亲-100122…
左子134 …
右子2-15 …
结构:
typedef
datatype
data;
int
parent;
lchild;
rchild;
}NODE;
NODE
tree[N];
//
生成N个结点的树
4)
二叉链表
5)
三叉链表
6)
哈夫曼树
5.二叉树的遍历
先根
中根
栈
中根遍历(左子树)根(右子树),再用相同的方法处理左子树,右子树.
后根
/
先,中序已知求树:
先序找根,中序找确定左右子树.
层次遍历(队列实现)
6.线索二叉树(穿线树)
中序线索二树树目的:
利用空指针直接得到中序遍历的结果.
手段(方法):
左指针为空,指向前趋,右指针为空,指向后继.
结点结构:
ltag
Lch
Data
rch
rtag
Ltag=0,lch指向左孩子,ltag=1,指向前趋结点
Rtag=0,rch指向右孩子;
rtag=1,指向后继结点
中序遍历:
1)
找最左结点(其左指针为空)
2)
当该结点的rtag=1,该结点的rch指向的就为后继
3)
当rtag=0,后继元素为右子树中最左边那个
N个结点的二树有空指针N+1个
排序查找是笔者觉得最头疼的算法了,常搞混去的啊.不知道各位学得如何,如果不错,还请告诉我一些经验!
查找
一、
知识点 /静态查找->
数组
1、
什么是查找
动态查找->
链树
●顺序查找,时间复杂度
O(n)
●折半查找:
条件:
有序;
时间复杂度
O(nlog2n)
(时间复杂度实际上是查找树的高度)
●索引查找:
第I+1块的所有元素都大于第I块的所有元素。
算法:
根据index来确定X所在的块(i)
时间复杂度:
m/2
在第I块里顺序查找X
时间复杂度:
n/2
总的时间复杂度:
(m+n)/2
●二叉排序树 1)定义:
左子树键值大于根节点键值;
右子树键值小于根的键值,其左右子树均为二叉排序树。
2)特点:
中序遍历有序->
(删除节点用到此性质)
3)二叉排序树的查找:
如果根大于要查找的树,则前左子树前进,如果根小于要查找的树,则向右子树前进。
4)结点的插入->
二叉排序树的构造方法
5)结点删除(难点)
1、右子树放在左子树的最右边
2、左子树放在右子树的最左边
●avl树(二叉平衡树):
左右子树高度只能差1层,即|h|<
=1其子树也一样。
●B树:
n阶B树满足以下条件 1)每个结点(除根外)包含有N~2N个关链字。
2)所有叶子节点都在同一层。
3)B树的所有子树也是一棵B树。
特点:
降低层次数,减少比较次数。
排序
一、知识点
1、排序的定义
/内排序:
只在内存中进行
2、排序的分类
外排序:
与内外存进行排序
内排序:
/直接插入排序
1)插入排序
shell排序
/冒泡排序
2)交换排序
快速排序
/简单选择排序
3)选择排序
堆
锦标赛排序
4)归并排序(二路)
5)基数排序(多关链字排序)
3、时间复杂度(上午题目常考,不会求也得记住啊兄弟姐妹们!
)
*
*
15
*
/稳定
*(前后不变)
排序
不稳定 *
*(前后改变)
经整理得:
选择、希尔、堆、快速排序是不稳定的;
直接插入、冒泡、合并排序是稳定的。
●锦标赛排序方法:
13 16 11 18 21 3 17 6
/ / / /
13 11 3 6
/ /
11 3
/
3(胜出,将其拿出,并令其为正无穷&
GoOn)
●归并排序方法:
13 16 11 18 21 3 17 6
/ / / /
13,16 11,18 3,21 6,17
11,13,16,18 3,6,17,21
/
3,6,11,13,16,17,18,21
●shell排序算法:
1)定义一个步长(或者说增量)数组D[m];
其中:
D[m-1]=1(最后一个增量必须为1,否则可能不完全)
2)共排m趟,其中第i趟增量为D[i],把整个序列分成D[i]个子序列,分别对这D[i]个子序列进行直接插入排序。
程序如下:
for(i=0;
m;
i++)
{for(j=0;
d[i];
j++)
{对第i个子序列进行直接插入排序;
注意:
下标之差为D[i];
}