题目
设计一个算法删除单链表L(有头结点)中的一个最小值结点。
分析
先谈谈我自己写的思路:(1)寻找到最小值结点,返回最小值结点的指针或者返回最小值结点在链表中的序号位置;(2)删除指定位置的最小值结点。
关于寻找链表中的最小值结点,可以先考虑将链表的开始结点(第一个结点)设置为最小值结点,然后将最小值结点与链表中的每个结点进行比较,如果比最小值结点小的话,就将该结点置为最小值结点,反之继续比较,最后返回。
核心代码如下:
/* 在单链表中查找结点元素data值最小的结点 */
/* *list指的是要查找最小值结点的链表 */
LNode * findMin(LNode *list) {
LNode *temp=list->next; // 开始结点
LNode *min=list->next; // 最小值结点,意思是将开始结点设置为最小值结点
while(temp!=NULL) { // 循环条件,当head!=NULL时
if(temp->data<min->data) { // 比较当前结点的数据与最小值结点的数据
min=temp; // 如果小于最小值的结点的数据,那么就将该结点设置为最小值结点
}
temp=temp->next; // 循环到下一个结点
}
return min; // 返回最小值结点
}
/* 删除单链表中最小值结点 */
/* *list指的是要操作的单链表;*minNode指的是要被删除的最小值结点 */
void deleteMinNode(LNode *list,LNode *minNode) {
LNode *temp=list->next;// 开始结点,即第一个结点
LNode *pre=list; // 头结点
LNode *tempDelNode; // 临时保存要被删除的结点
while(temp!=NULL) { // 循环遍历单链表中的所有结点
if(temp->data==minNode->data) { // 比较当前结点与最小结点的值是否相等,如果相等,则删除当前结点,否则继续寻找下一个
tempDelNode=temp; // 临时保存要被删除的最小值结点
pre->next=tempDelNode->next;// 将头结点指向被删除结点的下一个结点,实现删除操作连接新链表
free(tempDelNode); // 释放结点资源
break; // 跳出循环
} else { // 如果不相等,就去下一个结点进行判断
pre=temp; // 记录终端结点指向temp
temp=temp->next; // 到单链表的下一个结点
}
}
}
完整代码如下:
#include <stdio.h>
#include <stdlib.h>
// 声明单链表结构体
struct LNode {
int data;
struct LNode *next;
};
/* 通过用户输入数据创建一个单链表,由用户输入整型测试数据 */
/* 返回一个单链表 */
LNode * createList() {
LNode *head;
LNode *p1,*p2;
p1=p2=(LNode *)malloc(sizeof(LNode));
head=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
int i=0;
while(p1->data!=0) { // 当用户在控制台输入0时结束循环
i+=1;
if(i==1) {
head->next=p1;
} else {
p2->next=p1;
}
p2=p1;
p1=(LNode *)malloc(sizeof(LNode));
scanf("%ld",&p1->data);
}
p2->next=NULL;
return head;
}
/* 打印单链表 */
/* *list指的是要被打印输出的单链表 */
void printList(LNode *list) {
LNode *temp=list->next;// 单链表的开始结点
printf("\n");
while(temp!=NULL) { // 循环单链表
printf("%ld\t",temp->data); // 打印单链表中的data数据
temp=temp->next; // 遍历至下一个结点
}
printf("\n"); // 换行
}
/* 在单链表中查找结点元素data值最小的结点 */
/* *list指的是要查找最小值结点的链表 */
LNode * findMin(LNode *list) {
LNode *temp=list->next; // 开始结点
LNode *min=list->next; // 最小值结点,意思是将开始结点设置为最小值结点
while(temp!=NULL) { // 循环条件,当head!=NULL时
if(temp->data<min->data) { // 比较当前结点的数据与最小值结点的数据
min=temp; // 如果小于最小值的结点的数据,那么就将该结点设置为最小值结点
}
temp=temp->next; // 循环到下一个结点
}
return min; // 返回最小值结点
}
/* 删除单链表中最小值结点 */
/* *list指的是要操作的单链表;*minNode指的是要被删除的最小值结点 */
void deleteMinNode(LNode *list,LNode *minNode) {
LNode *temp=list->next;// 开始结点,即第一个结点
LNode *pre=list; // 头结点
LNode *tempDelNode; // 临时保存要被删除的结点
while(temp!=NULL) { // 循环遍历单链表中的所有结点
if(temp->data==minNode->data) { // 比较当前结点与最小结点的值是否相等,如果相等,则删除当前结点,否则继续寻找下一个
tempDelNode=temp; // 临时保存要被删除的最小值结点
pre->next=tempDelNode->next;// 将头结点指向被删除结点的下一个结点,实现删除操作连接新链表
free(tempDelNode); // 释放结点资源
break; // 跳出循环
} else { // 如果不相等,就去下一个结点进行判断
pre=temp; // 记录终端结点指向temp
temp=temp->next; // 到单链表的下一个结点
}
}
}
int main() {
/* [0.]创建初始测试单链表 */
LNode *list,*t1,*t2,*t3,*t4;
LNode *list2,*mergeList;
list=createList();// 创建测试链表
printList(list);// 打印单链表
t1=findMin(list); // 发现最小值结点
printf("min=%d",t1->data);// 打印输出最大值结点的data值
deleteMinNode(list,t1);// 删除最小值结点
printList(list);// 打印删除后的链表
return 0;
}
测试结果如下:
可以看出上面的代码比较多,看看参考书上的算法是怎么样的。
分析如下:用p从头至尾扫描链表,pre指向*p结点的前驱,用minp保存值最小的结点指针,minpre指向minp的前驱。一边扫描,一边比较,将最小值结点放到minp中。
代码如下:
void delminnode(LNode *L){
LNode *pre=L,*p=pre->next,*minp=p,*minpre=pre;
while(p!=NULL){
if(p->data<minp->data){
minp=p;
minpre=pre;
}
pre=p;
p=p->next;
}
minpre->next=minp->next; // 删除*minp结点
free(minp);
}
其实原理都是一样的,不过参考书上的代码确实要简洁得多。