线性表(linearList)
(1)线性表的定义:
节点(node)之间具有一对一的前驱后继关系
(2)线性表的存储结构:
(2.1)顺序表 (sequenceList):
(2.2)链式表 (linkList):
(3)顺序表的常见操作:
(初始化+增删改查+表的状态判断)
(3.0)追加(appendNode/addNode)一个节点(node、element) :
(3.1)在特定位置 i 插入(insertElementAt)一个节点:
(3.2)删除(deleteElementAt)某个特定位置 i 的节点 :
(3.3)查找(searchElement/find)值为value 的节点的位置i :
(3.4)改变(changeElementAt)某个节点 :
(3.5)遍历(traverse)整个表 :
(3.6)初始化(init),以及表空(isEmpty),表满(isFull)判断 :
(3.7)获取i号(getNodeAt/getElementAt)节点:
(3) 带头结点的单链表的 常见操作 :
(带有头节点主要是为了方便每个节点都可以有前驱,如果没有头节点,则第一个节点就没有前驱)
(3.1)获取某个节点以及其前驱节点 :
根据节点的值value获取:searchNode
根据索引获取i号节点: getNodeAt
(3.2)添加一个节点 addNode :
(先处理当前节点的next,在处理当前节点的前驱节点的next)
(即先处理该节点指出去的箭头,然后在处理指向该节点的箭头);
(头插法 :不断更新首节点)
(尾插法:不断更新尾节点)
在特定位置i 插入一个节点 insertNodeAt;
(通过调用getNodeAt)
(3.3)删除特定位置i的节点:deleteNodeAt;
(删除一个节点直接处理其前驱节点的next)
(即直接处理指向该节点的箭头。)
(通过调用getNodeAt)
通过节点的值value来删除某一个节点 :
(通过调用searchNode)
(3.4)遍历链表traverse.
(3.5)初始化链表头节点init,创建链表create
(不断构造节点,然后addNode即可),释放链表release.
(4)顺序表sequenceList 与 链式表linkList 的区别,优缺点 :
(4.1)区别与优缺点 :
(4.1.1)包含内容:
(1)顺序表包含的 有首节点的指针,以及节点个数len,以及顺序表大小size,就可以进行所有操作。(注:初始化len=0.添加一个元素则先填充元素到len位置,然后len++;所以填元素的范围为0~len-1)
但是链式表只需要包含首节点的指针(不带头节点),或者头节点的指针即可(带有头节点),就可以进行所有的操作。
(2)顺序表与链式表中节点的 定义也是不一样的,链式表中节点中需要加
一个next 指向下一个节点,但是顺序表中不需要。
(4.1.2)操作 :
(1)顺序表可以直接存取一个节点,但是链式表需要从头遍历存取i号元素;
(2)顺序表 增加,删除一个节点,需要移动其他节点,链式表可以直接添加,删除。
(3)由于链式表节点的地址不是连续的,并且node节点中,只有next,所以不可以通过一个节点
地址来找到其前驱节点,但是顺序表可以。
所以通常链式表操作中getNodeAt以及searchNode两个函数获取某一个节点地址,还要获取其前一个
节点的 地址,这样才可以插入一个节点。
(getNodeAt函数是通过索引i,查找到第i个节点。searchNode就是根据节点内容,找到某个节点。getNodeAt在顺序表以及链式表中都一样,但是searchNode在顺序表中,返回的是节点的索引i,但是在链式表中获得的是该节点指针以及其前驱节点指针,如果获取的是索引i,那么通过getNodeAt也可以获取到节点。)
(5)范例 :
(5.1)顺序表基本操作的范例 :
(5.2)单链表基本操作的范例 :
(5.3)单链表的应用之多项式的运算
---------
(6)单向链表 与 双向链表 的插入与 删除总结:
1)图解:
2)单链表的插入,删除解析:
插入:
先处理新节点new的出度:即new->next=p2;
再处理新节点new的入度:即p1->next=new;
删除:
直接将p2的入读连接p2的出度:即p1->next=p2->next;
3)双向链表的插入 ,删除解析;
插入:
先处理new的出度:即new->next=p2;new->prior=p1;
再处理new的入度:即 p1->next=new; p2->prior=new;
删除:
直接将p2的入读连接p2的出度:
即:p1->next=p3;p3->prior=p1;
-----------------------------------
(6) 双向链表 :
(6.1)双向链表图解,以及双向节点图解 :
图解:
(6.2)双向链表的插入 图解 及代码:
图解:
分析:链表节点的插入,先处理该节点指出去的箭头,然后在处理
指向该节点的箭头;
int InsertElemAfter(DBNODEPTR p, elemtype e)
{/*将数据元素e插入到某双向链表中结点p的后面*/
DBNODEPTR q;
q=(DBNODEPTR)malloc(sizeof(DBNODE));/*分配结点*/
if(q==NULL)return 0;
q->data=e;
q->next=p->next;/*①*/
q->prior=p; /*②*/
/*①②为处理该节点指出去的箭头,
③④为处理指向该节点的箭头*/
if(p->next!=NULL)
p->next->prior=q;/*③*/
p->next=q; /*④*/
return 1;
}
(6.3)双向链表的删除 图解 及代码:
图解:
分析:
删除节点直接处理指向该节点的箭头。
void DeleteElem(DBNODEPTR p)
{/*p是某双向链表中的结点,将p从链表中摘除并释放结点内存*/
DBNODEPTR pre;
pre=p->prior; /*pre指向p的前驱*/
if(pre!=NULL)
pre->next=p->next; /*①*/
if(p->next!=NULL)
p->next->prior=pre; /*②*/
free(p);/*释放p结点内存*/
}
(7) 单链表的操作扩展 :
(7.1)单链表的反转reverse :
(7.2)单链表的排序sort (快速,冒泡,插入,选择):
(7.3)单链表的节点追赶问题 :
(8)顺序表的扩展操作 :
(8.1)重复次数最多的元素 / 重复次数超过一半的元素 :
(8.2)最大和子数组 :
(8.3)最长升序子数组 :
(8.4)数组的反转,循环右移,循环左移 :
(9)注意事项 :
/*
(1)空节点的 处理 :
如果原链表中有空节点,则插入一个节点之后还是有空节点的,即使是插在最后一个节点之后。
因为最后一个节点的next为NULL,即NULL 的前驱为最后一个节点,即使是一个节点插在最后一个节点之后,
那么NULL 还是会有的。
所以,链表初始化的时候必须给尾节点的next置为NULL。
*/