数据结构代码题总结
题目01
设有一个带头节点的循环单链表,其结点值均为正整数,设计一个算法,反复找出单链表中结点值最小的结点,并输出,然后将该点从单链表中删除,直到单链表为空为止,在删除表头结点。
题目分析
1、针对以上的的题意进行分析,得到一般解题过程为:
- 先查找符合要求的最小值结点
- 进行删除
- 注意!!!!!!以上两个步骤只是建立在一趟单链表的遍历下删除了一个最小值结点
- 题目要求的是反复找出单链表中节点值最小的结点,并输出,然后将其删除,需要再设置一个循环进行遍历。
对于如何查找单链表的最小值结点,和删除当前的最小值结点,这里参考以前的文章中的第一题链接如下:
查找删除最小值结点
为方便比较这里先贴出,上一篇文章的查找和删除最小值结点的代码操作设计:
//因为要操作链表所以必要加&符号
//结构体
typedef struct LNode{
int data;
struct LNode * next;
};
ListLink Delete_min(ListList &L){
//初始化节点
LNode * pre = L;
LNode * p = pre->next;//指向头节点的下一个节点
LNode * minp = p;//min初始化
LNode * minpre = pre;//初始化前驱
while(p != null){
//核心代码
if(p->data < minp->data){
minp = p;
minpre = pre;
}else{
pre = p;
p = p->next;
}//不是当前的最小值
//删除查找的节点
//已经找到最小值的前驱
minpre->next = minp->next;
free(minp);
}
}
结合以上的代码片段,我们来完成对当前的题目的解答操作,
由于题目中要求我们要反复的进行查找循环单链表中的可以进行删除的元素,需要对其进行外加循环进行套用。
实现思路:
- 先设置一个大循环
- 循环中初始化相关的指针
- 包括pre,p,minp,minpre指针
- 进行查询
- 若不是最小值则pre和p进行后移
- 若是则进行删除
- 最后删除头节点
其完整代码如下:
typedef int ElemType;
//设置结构体
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
//删除全部需要删除的元素操作
void Delete_xAll(LinkList &L){
while(L->next != L){//L->next != L----这句话的代表着循环单链表的结束语句,
//即尾部节点指向头节点
LNode* pre = L;
LNode* p = L->next;
LNode* minp = p;
LNode* minpre = pre;//初始化操作指针
while(p!= L){//尾部结点指向头节点为停止
if(p->data < minp->data){
minp = p;
minpre = pre;
}
//为避免死循环,在找到最小值后,都要进行继续前进扫描最小值后面的节点没有找到最小值
//找到了最小值节点,为保证后续的节点可以访问到,这里相当于保存后继
pre = p;
p = p->next;
}
//二层循环的目的在于找到最小值
//放在二层循环外进行删除
minpre->next = minp->next;
//打印最小值节点数据
printf("%d",minp->next);
free(minpre);
}
//最后删除根节点
free(L);
}
相比于上面的代码,其修改之处便是一下:
1、
while(p!= L){//尾部结点指向头节点为停止
if(p->data < minp->data){
minp = p;
minpre = pre;
}else{
//没有找到最小值
pre = p;
p = p->next;
}
}
2、
while(L->next != L){//L->next != L----这句话的代表着循环单链表的结束语句,//即尾部节点指向头节点`}
解答完毕!
题目02
1、题目分析
- 首先是一个结点的属性有原来的,pred、data、next变为pred、next、data、freq进行设计
- 其次是按照题目的要求需要操作的实质是
- 通过Locate函数进行freq进行降序排序
2、算法思路
- 先找到含有x的结点,并对该节点的freq领域数据+1
- 在该链表上取下该结点
- 对其前驱结点进行往前查找,
- 查找到大于该节点的元素的下一个元素
- 执行双链表的插入结点操作。
这里进行分步骤实现代码的完整编写,先写核心代码:
1、先写结构体,并找到含有x的结点,并令freq+1;
typedef struct DNode
{
ElemType data;
struct LNode *pred,*next;
ElemType freq;
}DNode,*DLinkList;
//查找结点
while(p!=NULL && p->data==x){
p = p->next;
}
2、对于查找结束的条件有两个
- P为null,由于循环跳出了是代表着没有找到指定的x的结点
- p不为null,因此说明找到了节点值是x的结点
3、对其进行freq加1,并对其进行链表结点取出,
其+1的操作这里就不贴出了,对进行链表结点取出进行图解:
实现的代码如下:
p->next->pred = p->pred;//照应上面的图解进行结点的取出
p->pred->next = p->next;
4、往前进行前驱的查找结点的遍历,直到找到比结点x大的结点进行停止
进行插入结点。
这里对双链表的插入代码进行讲解一下:
先看图
其插入结点的代码的讲解如上:
结合以上的分步骤分析,完整代码如下:
//结构体
typedef struct DNode
{
ElemType data;
struct LNode *pred,*next;
ElemType freq;
}DNode,*DLinkList;
DLinkList Locate(DLinkList &L,ElemType x){
LNode * p = L->next;
LNode *q;//代表p的前驱
//查找
while(p!= NULL && p->data != x){
p = p->next;
}
if(p== NULL){
printf("%d\n", "查找失败");
exit(-1);
}else{
//查找成功
p->freq++;
//取出结点
p->next->pred = p->pred;
p->pred->next = p->next;
//寻找合适位置插入
q = p->pred;//设置p的前驱进行寻找
while(q != L && q->data <= p->data){
q = q->pred;//向前找
}
//找到了合适的位置进行结点插入
p->next = q->next;
q->next->pred = p;
p->pred = q;
q->next = p;
}
return p;
}
完整解答!!
题目03
已知带有头结点的单链表,设计对时间和空间尽可能高效的算法,查找链表的倒数第k个结点的数值,并打印返回1,若没有找到返回0
题目分析:
- 若不考虑时间复杂度,对其进行第一次遍历得到单链表的长度,第二次遍历访问length-k的数值。
- 若不考虑时间复杂度的概念,第一次遍历,并存储在数组中,第二次访问数组的length-k+1的位置元素
但是要求是考虑时间和空间复杂度,因此以上的两个方法都不适用。
算法新思路
- 正着数第k个数值,
- 找到尾指针进行间隔移动
其实现的代码图解如下:
其实现思路为:
p先向后移动k个单位,,然后p和q在一起后移,直到p为kong到达表尾,此时q所指向的元素便是倒数第k个结点的数值。
其完整代码如下:
typedef int ElemType;
//设置结构体
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
//核心代码
int Search_x(LinkList list,ElemType k){
LNode * p = list->next;
LNode * q = list->next;
int count = 0;//设置计数
while(p!=NULL){
if(count < k){
count++;
p =p->next;
}else{
p = p->next;
q = q->next;//p到达指定位置,同时移动p和q
}
}
if(count<k){
return 0;//失败查找
}else{
return 1;//成功查找
}
}
算法学习加油!
注:
个人代码问题或需要程序编写辅导服务等问题请加闲鱼【代码无bug】
或点击下面链接跳转闲鱼进行咨询