复习一次链表的基本操作
网上找到一位大佬的代码
重新学习链表
跟着他的代码重新打了一遍
受益匪浅
最后在测试阶段采用文件重定向的方式
避免多次输入数据
#include <bits/stdc++.h>
using namespace std;
struct Student
{
int num;//学号
double score;//分数,其他信息可以继续在下面增加
struct Student *next;//指向下一节点的指针
};
int n;//节点总数
/*
=========================
功能:创建n个节点的链表
返回:指向链表表头的指针
=========================
*/
struct Student * Create()
{
struct Student *head;//头节点
struct Student *p1=NULL;//p1保存创建的新节点的地址
struct Student *p2=NULL;//p2保存原链表最后一个节点的地址
n=0;//创建前为空链表
p1=( struct Student *)malloc( sizeof(struct Student) );//开辟一个新节点
p2=p1; //如果开辟成功,p2把它的指针保存下来以备后用
if(p1==NULL)//节点开辟失败
{
cout << "\nCann't create it, try it again in a moment!\n";
return NULL;
}
else//节点开辟成功
{
head=NULL;//开始head指向NULL
cout << "Please input " << n+1 << " node -- num,score: \n";
cin >> p1->num >> p1->score ;
}
while(p1->num !=0)//只要学号不为0,就继续录入下一节点
{
n++;//节点总数增加一个
if(n==1)//如果节点总数是1,则head指向刚创建的节点p1
{
head=p1;
p2->next =NULL;//此时p2和p1相同,也就是让p1-next指向NULL
}
else
{
p2->next =p1;//指向刚刚开辟的新节点
}
p2=p1;//把p1的地址给p2保留,然后p1开辟新节点
p1=(struct Student *)malloc( sizeof(struct Student) );
cout << "Please input " << n+1 << " node -- num,score: \n";
cin >> p1->num >> p1->score ;
}
p2->next =NULL;//单向链表最后一个节点指向NULL
free(p1);//释放p1
p1->next =NULL;//将清空的变量置NULL
return head;//返回创建链表的头指针
}
/*
=========================
功能:输出节点
返回:void
=========================
*/
void Print(struct Student *head)
{
struct Student *p;
cout << "\nNow , These " << n << " records are:\n";
p=head;
if(head!=NULL)//只要链表非空,就输出链表中所有节点
{
cout << "head is " << head << "\n";//输出头节点指向地址
do
{
cout << p << " " << p->num << " "<< p->score << " "<< p->next << endl;
//依次输出当前节点地址 字段值 下一节点地址
p=p->next ;//移动到下一节点
}
while(p!=NULL);
}
}
/*
=========================
功能:删除指定节点(此例中是删除指定学号的节点)
返回:指向链表表头的指针
=========================
*/
struct Student *Del(struct Student *head,int num)
{
struct Student *p1;//p1保存当前需要检查的节点地址
struct Student *p2;//p2保存当前检查过的节点地址
if(head==NULL)//若是空链表
{
cout << "\nList is NULL!\n" ;
return head;
}
//定位要删除的节点
p1=head;
while(p1->num != num && p1->next != NULL)//p1的节点不是要删除的,且不是最后一个节点
{
p2=p1;//保存当前节点地址
p1=p1->next ;//后移一个节点
}
if(p1->num == num)//找到要删除的节点
{
if(p1==head)//若是头节点
{
head=p1->next ;
}
else//若是其他节点
{
p2->next = p1->next ;
}
free(p1);//释放当前节点
p1=NULL;//将清空的变量置NULL
cout << "\ndelete " << num << " success!\n";
n--;//节点总数减一
}
else//没有找到
{
cout << "\n" << num << " not been found!\n";
}
return head;
}
/*
=========================
功能:插入指定节点的后面(此例是指定学号的节点)
返回:指向链表表头的指针
=========================
*/
struct Student *Insert(struct Student *head,int num,struct Student *node)
{
struct Student *p1;//p1保存当前需要检查的节点的地址
if(head==NULL)//若为空链表
{
head=node;
node->next =NULL;
n++;
return head;
}
p1=head;
while(p1->num != num && p1->next != NULL)//p1不是我们要查找的节点,并且它不是最后一个节点
{
p1=p1->next ;//p1后移
}
if(p1->num == num)//若找到了节点
{
node->next = p1->next ;
p1->next = node;
n++;
}
else//若找不到节点
{
cout << "\n" << num << " not been found!\n";
}
return head;
}
/*
=========================
功能:反序节点
(链表的头变成尾,尾变成头)
返回:指向链表表头的指针
=========================
*/
struct Student *Reverse(struct Student *head)
{
struct Student *p;//临时存储
struct Student *p1;//存储返回结果
struct Student *p2;//源结果节点一个个地取
p1=NULL;//开始颠倒时,已颠倒部分为空
p2=head;//p2指向链表头节点
while(p2!=NULL)
{
p=p2->next ;//临时存储p2的next节点
p2->next =p1;//然后改变p2的next节点
p1=p2;//用p2赋值给p1
p2=p;//p2后移到原链表的下一位置
}
head=p1;
return head;
}
/*
=========================
功能:直接插入排序(从小到大)
返回:指向链表表头的指针
=========================
*/
struct Student *InsertSort(struct Student *head)
{
struct Student *first;//为原链表剩下用于直接插入排序的节点头指针
struct Student *t;//临时指针变量,插入节点
struct Student *p,*q;//临时指针变量
first=head->next ;
head->next =NULL;//只含一个节点的有序链表
//整个链表相当于变成时两个链表
while(first != NULL)//遍历剩下的无序链表
{
for(t=first,q=head,p=NULL;(q != NULL) && (q->num < t->num );p=q,q=q->next );
/*
让q从头开始
当q不指向NULL 且 q->num < t ->num
p=q,q后移
最后p,q定位到t需要插入的前后位置
*/
first=first->next ;//first后移
if(q==head)
{
head=t;
}
else
{
p->next =t;
}
t->next =q;
}
return head;
}
/*
=========================
功能:冒泡排序(从小到大)
返回:指向链表表头的指针
=========================
*/
struct Student *BubbleSort(struct Student *head)
{
struct Student *endpt;//控制循环比较
struct Student *p;//临时指针变量
struct Student *p1,*p2;
p1=(struct Student *)malloc( sizeof(struct Student) );//开辟新节点
p1->next =head;//我们增加一个节点,放在第一个节点前面
//主要是为了便于比较,因为第一个节点没有前驱,不能交换地址
head=p1;//让head指向p1,排序完成后再释放掉
for(endpt=NULL;endpt!=head;endpt=p)//从后向前,这样后面的节点都是排序好的
{
for(p=p1=head;p1->next ->next != endpt;p1=p1->next )
{
if(p1->next ->num >p1->next ->next ->num)
{
p2=p1->next ->next;//完成两节点的交换
p1->next ->next =p2->next ;
p2->next =p1->next ;
p1->next =p2;
p=p1->next ->next ;
}
}
}
p1=head;
head=head->next ;
free(p1);
p1=NULL;
return head;
}
/*
=========================
功能:插入有序链表的某个节点后面(从小到大)
返回:指向链表表头的指针
=========================
*/
struct Student *SortInsert(struct Student *head,struct Student *node)
{
struct Student *p;//p保存当前需要检查的节点的地址
struct Student *t;//临时指针变量
if(head==NULL)//处理空链表
{
head=node;
node->next =NULL;
n++;//节点总数加一
return head;
}
p=head;//有序链表非空
while(p->num <node->num && p != NULL)//p的num小于node的num,且p不等于NULL
{
t=p;//保存当前节点的前驱,以便后面处理
p=p->next ;//p后移一个节点
}
if(p==head)//刚好插在第一个节点之前
{
head=node;
}
else//插在其他节点之后
{
t->next =node;
}
node->next =p;//加入node节点
n++;//节点总数加一
return head;
}
/*
=========================
功能:销毁链表
返回:void
=========================
*/
void DestoryList(struct Student *head)
{
struct Student *p;
if(head==NULL)
{
return ;
}
while(head)
{
p=head->next ;
free(head);
head=p;
}
return ;
}
int main()
{
ifstream fin("input.txt"); // 已有输入文件
streambuf *cinbackup;
cinbackup= cin.rdbuf(fin.rdbuf()); //用 rdbuf() 重新定向
/*
如果不用文件重定向
就把上面这几行及倒数第二行cin.rdbuf(cinbackup);
删除即可
*/
struct Student *head,*stu;
int Num;
//测试Create,Print
head=Create();
Print(head);
//测试Del
cout << "\nWhich one delete: ";
cin >> Num;
head=Del(head,Num);
Print(head);
//测试Insert
stu=(struct Student *)malloc(sizeof(struct Student));
cout << "\nPlease input the insert node -- num,score";
cin >> stu->num >> stu->score ;
cout << "\nInsert behind num: ";
cin >> Num;
head=Insert(head,Num,stu);
Print(head);
//测试Reverse
cout << "\nReverse the linklist: \n";
head=Reverse(head);
Print(head);
//测试InsertSort
cout << "\nInsertSort the linklist: \n";
head=InsertSort(head);
Print(head);
//测试BubbleSort
cout << "\nBubbleSort the linklist: \n";
head=BubbleSort(head);
Print(head);
//测试SortInsert
cout << "\nSortInsert the linklist: \n";
stu=(struct Student *)malloc(sizeof(struct Student));
cout << "\nPlease input the insert node -- num,score";
cin >> stu->num >> stu->score ;
head=SortInsert(head,stu);
Print(head);
//销毁链表
DestoryList(head);
cin.rdbuf(cinbackup); // 取消,恢复键盘输入
return 0;
}