《大话数据结构》阅读笔记。第二天。2018-7-24

单链表的第i个位置元素获取:

1.声明一个节点p,指向第一个结点,从j=1 开始遍历,并当j<i时继续

2.链尾时则不存在

3.成功则返回数据

status GetElem(LinkList L, int i, ElemType *e)

{

int j=1;

LinkList p=L->next;

while ( p && j<i )

{

p = p -> next;

j ++;

}

if ( !p || j>i )

{

 return E;}

*e = p->next;

return ok;

}

再第i个位置插入s结点:

1.创建x新结点s,用malloc。s=(LinkList)malloc(sizeof(Node));

malloc:          p = (type*)malloc(sizeof(type))  LinkList=Node *  

2.不能直接到第i位置,需要从头遍历。

3.先获取到第i个结点p

4.s->next=p->next      p->next=s

删除q结点

p->next =p->next->next(这没看懂程杰什么意思,为什么要p->next=q,q不应该本来就在的),

free(q)收回q

优点:对于插入或删除数据越频 繁的操作,单链衰的效率优势就越是明显。

创建单链表:

1.声明一结点p和计数器i;

2.初始化空链表L,L的头结点的指针指向NULL;

3.头插法for:生成一新结点幅值给p;p->=(*L)->next;(*L)->next=p

4.尾插法for: r->next=p;r=p    r始终指向表尾。 r->next=NULL.

单链表整表删除

q=p->next;free(p);p=q不能直接删除,这样next就找不见了,

优缺点:

1.存储分配方式:顺序存储结构用一段连 续的存储单元依次存储 线性袤的数据元素。

                          单链表采用链式存储结 构,用干组任意的存储 单元存也钳主袤的元素。

2.查找:顺序O(1),单链表O(n)

  插入和删除:顺序O(n),单链表O(1)

  空间:顺序一开始要固定的大小。单链表不需要分配,个数不限

所以:当查找用的多时用顺序,插入删除用的多用单链表。还有元素个数。

其他链表结构:静态链表

用数组来代替指针。首先让数组元素都有两个数据域组成,data和cur。这种叫静态链表。

(感觉这个没什么用,有指针不需要这个)

循环链表:

将单链表中终结点的指针端由空指针指向头结点。

从任何一个结点出发可以访问全部链表。单链表的循环判断为p->next是否为空,现在为p->next不等于头结点。采用尾指针方便,此时头指针九尾s->next。

双向链表:

每个结点设置前驱结点*prior。

p\r插入s: s->prior、s->next、p->next、r->prior

p\s\r删除s:  p->next=r、r->prior=p

第四章 栈与队列

栈stack:撤销、后退、历史倒退。

仅在栈顶进行插入push和删除pop操作。    栈底封闭固定。     后进先出。

是个线性表(有前驱和后继的关系)。

栈的顺序存储结构实现:

用数组0端作为栈底,栈顶为top。当栈只有一个元素时,top=0。当top=-1时,说明为空栈。定义为

typedef int SElemType;       /*  SElemType(为栈内元素的类型,这里是int)  */

typedef struct

{

SElemType data[MAXSIZE];

int top;       /*  栈顶指针  */

}SqStack;

Push:    S->top++;S->data[S->top]=e;                      O(1)

POP:     *e=s->data[s->top]; s->top--;                       O(1)

两栈共享空间:

栈1top1;栈2top2。合并成一块空间。两端是两个栈底。

top1:~n-1   top2:n-1~0。  top1+1=top2 则栈满。

栈的链式存储结构及实现

又叫链栈。 单链表头部和栈顶合二为一。此时不需要头结点。   基本不存在栈满情况。  空栈时top=NULL。

typedef struct StackNode            /*链*/

{

 SElemType data;           /* SElemType为数据类型,这里为int */

struct StackNode *next;

}StackNode,*LinkStackPtr;

typedef struct LinkStack            /*栈*/

{

LinkStackPtr  top;

int  count;

}LinkStack;

进栈push:

status Push(LinkStack *S, SElemType e)      /*  status代表的是int,函数返回的也是int */

{

LinkStackPtr s=(LinkStackPtr)malloc(sizeof(LinkStcakPtr);

s->data=e;                                    /* 开辟新结点s,放元素e,在把结点指针指向top */

s->next=s->top;

S->top=s;

S->count++;

return ok;

)                                                 O(1)

出栈POP:

*e=S->top->data;  p=S->top; S->top=S->top->next;  free(p); S->count--;             O(1)

对比栈的顺序和链:

时间复杂度一样。空间:顺序需要固定长度,但存取时定位方便S->data[S->top];链栈长度无限制,但要放指针。

递归:函数自己调用自己

斐波那契数列:

int Fbi (int i) 

{

if (i<2)

  { return i==0?0:1;} 

return   Fbi(i-1)+Fbi(i-2);  

}

这种存储某些数据,并在后面又以存储的逆序恢复这些数据。使用栈。前行阶段,对于每一层递归,函数的局部变量、参数值以及返回地址都被压入栈,在退回阶段,栈顶的东西被弹出,逐步返回代码的层次。

中后缀表达这块没看。感觉很奇怪

队列:

允许在一端 插入(队尾) 另一端 删除(队头6) 的线性表。先进先出。

应用广泛,实时输出类的,键盘、显示屏等。

队列的顺序存储:

front指针指向队尾(出队)

rear指针指向队尾(入队)

当front=rear时就空了,当不断加入的时候,rear不断往后,会出现假溢出。后面溢出了,前面还空着。  若采用循环队列。

rear可以指向0,但是rear会和front重合,其实是满了。但是如何判断。 满了。rear和front相差一个位置时就认为是满了:(rear+l) %QueueSlze ==front

循环队列长度:(Q. rear-Q.Xront+MAXSTZE) %MAXSIZE

入队:Q→data(Q->zear)=e  元素给队尾;Q->rear= (Q->rear+l) %MAXS工ZE;rear指针向后移一位

出队:*e=Q->data[Q->fron];Q->front- (Q->front+l) %MAXSIZE;front指针向后移一位,最后则转头部。 O(1)

队列的链式存储:

线性表的单链表,只能尾进头出。又叫链队列。

入队:先分配一个结点(用malloc),在给他s->data=e。s->next=NULL。原队尾rear的next为s,在把s设为队尾。

出队:头结点的后继结点出队,头结点的后继改为出队那个的next。若队头也是队尾,则需将rear=front。  O(1)

总结:

栈,表尾进行插入删除,类型相同时可以共享。队列:一端进一端出。

很高兴今天完成了目标,本来20分钟前想放弃的,但是0.99*0.99*0.99=很小的数。

明天看完第五章。

猜你喜欢

转载自blog.csdn.net/weixin_41982696/article/details/81178814
今日推荐