- 花了三天时间,终于将与链表相关的操作写完了,特此记录一下,以备复习
/*********************************************************************
*
* 功能:实现与链表有关的操作,包括创建、遍历、插入和删除链表等
* 作者:khq
* 时间:2020年4月13日
*
**********************************************************************/
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//定义节点
typedef struct Node{
int data; //数据域
struct Node *pNext; //指针域
}NODE,*PNODE;
//函数声明
PNODE create_link(); //创建链表
void traverse_link(PNODE ); //遍历整个链表
bool is_empty(PNODE); //判断链表是否为空
int lenth(PNODE); //获取链表长度
bool insert_link(PNODE,int pos,int e); //在位置pos处插入元素e,成功,返回true,否则,返回false
bool delete_link(PNODE,int pos,int *e); //将位置pos处的元素删除,并将删除的元素给e,删除成功,返回true,否则,返回false
void sort(PNODE); //对链表元素进行排序
int main(void){
PNODE node = create_link(); //创建链表
traverse_link(node); //遍历链表
printf("判断链表是否为空,非空,将打印链表长度......\n");
if(is_empty(node)){
printf("链表为空!......\n");
printf("链表的长度:lenth =%d \n", lenth(node));
}else{
printf("链表非空!......\n");
printf("链表的长度:lenth = %d \n", lenth(node));
}
int position = 5;
printf("开始在链表的第%d个位置插入元素: %d \n",position,position*2);
insert_link(node,position,position*2);
printf("插入元素后,新的链表的长度lenth = %d \n", lenth(node));
traverse_link(node);
printf("开始在链表的第%d个位置删除元素: \n",position);
int e;
delete_link(node,position,&e);
printf("被删除的元素: %d\n",e);
printf("删除元素后,新的链表的长度lenth = %d \n", lenth(node));
traverse_link(node);
printf("开始为链表排序......\n");
sort(node);
traverse_link(node);
return 0;
}
//创建链表
PNODE create_link(){
//首先创建一个头结点,不保存有效数据
PNODE pHead = (PNODE)malloc(sizeof(PNODE));
if(pHead==NULL){
printf("链表创建失败,程序退出!\n");
exit(-1);
}
//创建一个结点,始终指向链表的尾部
PNODE pToil = pHead;
pToil->pNext = NULL; //NULL要大写
//确定链表的长度
int len;
printf("请输入链表的长度:\n");
scanf("%d",&len);
//临时保存链表上的每一个节点的值
int val;
for(int i=0;i<len;i++){
printf("第%d个节点上的值为:\n",i+1);
scanf("%d",&val);
//为每个新的节点分配内存空间
PNODE pNew = (PNODE)malloc(sizeof(PNODE));
if(pNew==NULL){
printf("节点内存分配失败,程序退出!\n");
exit(-1);
}
pNew->data = val;
pToil->pNext = pNew;
pNew->pNext = NULL;
pToil = pNew;
}
return pHead;
}
//遍历整个链表
void traverse_link(PNODE node){
PNODE traverseAll = node->pNext;
printf("显示链表中的元素......\n");
while(traverseAll!=NULL){
printf("%d ",traverseAll->data); //格式化的输入和输出
traverseAll = traverseAll->pNext;
}
printf("\n");
}
//判断链表是否为空,不是判断某一个有效节点,而是要传入头结点
bool is_empty(PNODE node){
PNODE isEmpty = node->pNext; //node看做头指针,p是首指针
if(isEmpty==NULL){
return true;
}
else{
return false;
}
}
//获取链表长度
int lenth(PNODE node){
int len = 0; //记录链表的长度
PNODE link_length = node->pNext;
while(link_length!=NULL){
len = len+1;
link_length = link_length->pNext;
}
return len;
}
//在位置pos处插入元素e,成功,返回true,否则,返回false,考虑在首和尾的情况
bool insert_link(PNODE node,int pos,int e) {
/*********************************************************************
*1、若链表为空,或pos不满合适条件,返回false
*2、获取首节点,并定义一个计数器count,记录链表的位置
*3、获取链表长度,对链表进行遍历看count是否为pos
*4、若为pos,则为新的节点分配内存空间,并将其插入到链表中,返回true
*5、否则,继续寻找,若到达链表尾部也没有找到,则返回false
**********************************************************************/
int count = 0;
PNODE pFirst = node->pNext; //p是首节点
PNODE pFormer = pFirst; //始终是p的前一个节点,除第一个节点之外
// if(is_empty(node)) //不必判断,在pos判断中已包括非空判断
// return false;
int len=lenth(node);
if(pos<1||pos>len+1) //考虑在首尾插入的情况
return false;
while(pFirst!=NULL){ //不要用is_empty来判断,否则,会出现最后一个元素没有插入的情况
count++;
if(count==pos){ //找到插入点之前的那个节点
PNODE pNew = (PNODE)malloc(sizeof(PNODE));
if(pNew==NULL){
printf("内存开辟失败!准备退出......\n");
exit(-1);
}
pNew->data = e;
if(count==1){
pNew->pNext = pFirst;
node->pNext = pNew;
}else{
pNew->pNext = pFirst;
pFormer->pNext = pNew;
}
return true;
}else{
pFormer= pFirst; //当前指针的前一个
if(count==len)
break;
pFirst=pFirst->pNext; //当前指针的下一个
}
}
if(count+1==pos){ //在尾部下一个点插入,包含链表为空的情况
PNODE pNew = (PNODE)malloc(sizeof(PNODE));
if(pNew==NULL){
printf("内存开辟失败!准备退出......\n");
exit(-1);
}
pNew->data = e;
pNew->pNext =NULL;
if(node->pNext==NULL) //链表为空时
node->pNext = pNew;
else
pFormer ->pNext = pNew;
return true;
}
}
//将位置pos处的元素删除,并将删除的元素给e,删除成功,返回true,否则,返回false
bool delete_link(PNODE node,int pos,int *e){
int count = 0;
int len = lenth(node);
if(pos<1||pos>len) //已隐含非空判断
return false;
PNODE pNow = node->pNext; //记录当前节点,初始化为首节点,以后要被删除的节点
PNODE pFront = pNow; //记录当前节点前面那个节点
while(pNow!=NULL){
count++;
if(count==pos){
*e = pNow->data; //保存被删除节点的数据
if(count==1){
node->pNext = node->pNext->pNext;
}else{
pFront ->pNext = pFront ->pNext->pNext;
}
return true;
}else{
pFront = pNow;
pNow = pNow ->pNext;
}
}
}
//对链表元素进行排序,选择排序
void sort(PNODE node){
if(is_empty(node)){
printf("链表为空,不能排序,准备退出......\n");
exit(-1);
}
int temp;
/********************************************************
//选择排序
for(PNODE pNow = node->pNext;pNow!=NULL;pNow=pNow->pNext){
for(PNODE pLater = pNow->pNext; pLater!=NULL;pLater = pLater->pNext){
if(pNow->data>pLater->data){
temp = pNow->data;
pNow->data = pLater->data;
pLater->data = temp;
}
}
}
*********************************************************/
//冒泡排序
for(PNODE pNow = node->pNext;pNow!=NULL;pNow=pNow->pNext){
for(PNODE pLater = node->pNext; pLater->pNext!=NULL;pLater = pLater->pNext){
if(pLater->data>pLater->pNext->data){
temp = pLater->data;
pLater->data = pLater->pNext->data;
pLater->pNext->data = temp;
}
}
}
}
结果:
感悟一下:关于链表的删除操作,如果用malloc函数为临时节点分配内存空间,按照如下的思路进行删除时:
调试时总显示DEMAGE的问题,索性不使用malloc,按照上面的代码,就ok了。