数据结构之链表的创建、遍历、判断、插入和删除以及排序算法

  • 花了三天时间,终于将与链表相关的操作写完了,特此记录一下,以备复习
 /*********************************************************************
 *
 * 功能:实现与链表有关的操作,包括创建、遍历、插入和删除链表等
 * 作者: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了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值