9.20 数据结构-单链表

单链表实现学生管理系统

程序的结构体数据类型使用int型替代学生结构体,其他内容都ok

1.创建单链表
PLink create(){//创建头节点
	PLink P=(PLink)malloc(sizeof(mylink));
	if(NULL==P){
		perror("create error");
		return NULL;
	}
	P->len=0;
	P->next=NULL;
	return P;//返回头节点地址
}
2.头插法
int front_insert(PLink L,int a){//头部插入元素
	if(NULL==L){
		printf("单链表不存在,创建失败\n");
		return -1;
	}
	PLink P=(PLink)malloc(sizeof(mylink));//申请新节点
	P->data=a;//数据域赋值
	P->next=L->next;//连线右边
	L->next=P;//连线左边//顺序不能颠倒
	L->len++;
	return 0;
}
3.尾插法 
int rear_insert(PLink L,int a){//尾部插入元素
	if(NULL==L){
		printf("单链表不存在,创建失败\n");
		return -1;
	}
	PLink t=L;
	for(int i=0;i<L->len;i++){//遍历单链表,找到尾,因为尾插是在最后节点后面即len+1位置插入
	                      	//,所以我们遍历len次,不是len-1次,找到len+1节点的前面节点
		t=t->next;
	}
	PLink P=(PLink)malloc(sizeof(mylink));//申请新节点
	P->data=a;//数据域赋值
	t->next=P;
	P->next=NULL;
	L->len++;
	return 0;
}
4.遍历单链表 
int output_link(PLink L){//遍历单链表
	int i;
	PLink t=L;
	for(i=0;i<L->len;i++){//遍历len次
		t=t->next;
		printf("%d\t",t->data);//打印数据域
	}
	printf("\n");
	return 0;
}
 5.任意位置插入元素
int anypos_insert(PLink L,int post,int key){
	if(NULL==L||post<1||post>L->len+1){
		printf("任意位置插入失败\n");
		return -1;
	}
	int i;
	PLink t=L;
	for(i=1;i<post;i++){//移动post-1次指向待插入节点的前驱
		t=t->next;
	}
	PLink P=(PLink)malloc(sizeof(mylink));//申请新节点
	P->data=key;//数据域赋值
	P->next=t->next;//指向右边
	t->next=P;//指向左边//顺序不能颠倒
	L->len++;//长度+1
	return 0;
}
6.任意位置删除元素 
int anypos_delete(PLink L,int post){
	if(NULL==L||post<1||post>L->len||L->len==0){
		printf("任意位置删除失败\n");
		return -1;
	}
	int i;
	PLink t=L;
	for(i=1;i<post;i++){//移动post-1次指向待删除节点的前驱
		t=t->next;
	}
	PLink Q=t->next;//保留要删除的节点地址
	t->next=t->next->next;//跨过要删除节点
	L->len--;//长度-1
	free(Q);//释放要删除的空间
	Q=NULL;//指针置空
    return 0;
}
7.任意位置查找元素 
int anypos_find(PLink L,int post){
	if(NULL==L||post<1||post>L->len){
		printf("任意位置查找失败\n");
		return -1;
	}
	int i;
	PLink t=L;
	for(i=0;i<post;i++){//移动post次后,t指向post节点
		t=t->next;
	}
	printf("找到了,该节点数据为:%d\n",t->data);
	return 0;
}
8.任意位置修改元素 
int anypos_change(PLink L,int post,int key){
	if(NULL==L||post<1||post>L->len){
		printf("任意位置修改失败\n");
		return -1;
	}
	int i;
	PLink t=L;
	for(i=0;i<post;i++){//移动post次后,t指向post节点
		t=t->next;
	}
	t->data=key;//修改post位置节点数据内容
	printf("修改成功\n");
	return 0;
}
9.头删法 
int front_delete(PLink L){
	if(NULL==L||L->len==0){
		printf("头删失败\n");
		return -1;
	}
	PLink Q=L->next;//保留要删除的节点地址
	L->next=L->next->next;//跨国要删除的节点
	L->len--;//长度-1
	free(Q);//释放要删除节点空间
	Q=NULL;//释放后指向地址置空
	return 0;
}
 10.尾删法
int rear_delete(PLink L){
	if(NULL==L||L->len==0){
		printf("尾删失败\n");
		return -1;
	}
	PLink t=L;
	int i;
	for(i=1;i<L->len;i++){//执行len-1次找到尾节点的前一个节点
		t=t->next;
	}
	PLink Q=t->next;//保留尾节点的地址
	t->next=NULL;//尾节点删除
	L->len--;//长度-1
	free(Q);//释放尾节点空间
	Q=NULL;//指针置空
	return 0;
}
 11.按值删除所有相同元素
int value_all_delete(PLink L,int value){
	if(NULL==L||L->len==0){
		printf("按值删除失败\n");
		return -1;
	}
	PLink t=L;
	int i,sub=-1;
	for(i=0;i<L->len;i++){
		if(t->next->data==value){//按值删除所有相同的值
			PLink Q=t->next;//存储要删除节点地址
			t->next=t->next->next;//跨过要删除节点
			L->len--;//长度-1
			free(Q);//释放删除节点空间
			Q=NULL;//指针置空
			sub=0;
			i--;
			continue;//删除一个节点后,不让t指向下一个节点,避免前后节点数据值相同,t移动导致漏删!!!
		}
		t=t->next;//遍历链表
	}
	if(sub==-1){
		printf("链表中没有相同的值,删除失败\n");
		return -1;
	}
	return 0;
}
12.按值删除最后相同元素 
int value_last_delete(PLink L,int value){
	if(NULL==L||L->len==0){
		printf("按值删除失败\n");
		return -1;
	}
	PLink t=L,Q;
	int i,sub=-1;
	for(i=0;i<L->len;i++){
		if(t->next->data==value){
			Q=t;//保留要删除最后节点前一个节点地址
			sub=0;
		}
		t=t->next;//遍历链表
	}
	if(sub==0){
		PLink W=Q->next;//保留要删除节点的地址
		Q->next=Q->next->next;//跨过要删除节点
		L->len--;//长度-1
		free(W);//释放要删除节点空间
		W=NULL;//指针置空
		return 0;
	}else{
		printf("链表中没有相同的值,删除失败\n");
		return -1;
	}
}
 13.按值修改最后相同元素
int value_last_change(PLink L,int key,int value){
	if(NULL==L){
		printf("按值修改失败\n");
		return -1;
	}
	PLink t=L,Q;
	int i,sub=-1;
	for(i=0;i<L->len;i++){
		t=t->next;//遍历链表
		if(t->data==key){
			Q=t;//保留要修改最后节点的地址
			sub=0;
		}
	}
	if(sub==0){
		Q->data=value;
		printf("修改成功\n");
		return 0;
	}else{
		printf("链表中没有相同的值,修改失败\n");
		return -1;
	}
}
14.按值查找最后相同元素并输出地址
int value_all_find(PLink L,int value){
	if(NULL==L){
		printf("按值查找失败\n");
		return -1;
	}
	PLink t=L;
	int i,sub=-1;
	for(i=0;i<L->len;i++){
		t=t->next;//遍历链表
		if(t->data==value){
			printf("找到了,地址为%p\n",t);
			sub=0;
		}
	}
	if(sub==-1){
		printf("链表中没有找到相同的值,查找失败\n");
	}
	return 0;
}
 15.逆序单链表
int reverse_link(PLink L){
	if(NULL==L){
		printf("逆序失败\n");
		return -1;
	}
/*  第一种逆序方式
    PLink temp=L->next;
	PLink next_node=L->next;//保留下一个节点的地址,避免丢失
	while(temp!=NULL){//temp与next_node错开一个节点,temp进行头插操作,实现逆序
	next_node=next_node->next;
	temp->next=L->next;
	L->next=temp;
	temp=next_node;
	}
	temp=L->next;//若开辟一个新的头节点且next初始化为NULL,则不需要下面操作
	for(int i=0;i<L->len;i++){
		temp=temp->next;	
	}
	temp->next=NULL;
	*/
	//第二种逆序方式
	PLink Q,t;
	Q=L->next;//指向第一个节点
	t=Q->next;//指向第二个节点
	while(t!=NULL){
		Q->next=t->next;//将1号和3号节点链接上
		t->next=L->next;//头插操作
		L->next=t;
		t=Q->next;//进行下一轮节点插入
	}
}
16.链表去重 
int repeat_link(PLink L){
	if(empty(L)){
		printf("链表去重失败\n");
		return-1;
	}
	/*第一种方式,i和j都是int,不是指针
	PLink Q=L,W;
	for(int i=0;i<L->len;i++){
		Q=Q->next;
		W=Q;//一轮循环下来,W应重新赋值指向Q的节点
		for(int j=i+1;j<L->len;j++){
			if(Q->data==W->next->data){
				PLink Z=W->next;
				W->next=W->next->next;
				L->len--;
				free(Z);
				Z=NULL;
				j--;//多执行一次避免漏删
				continue;//多个重复项连续存在时,避免漏删
			}
			W=W->next;
		}
	}*/
	//第二种方式,i和j都是指针,比第一种优化一些
	PLink i,j;
	for(i=L->next;i->next!=NULL;i=i->next){
		for(j=i;j->next!=NULL;){
			if(i->data==j->next->data){//注意删除是要j指向前一节点地址
				PLink t=j->next;//保留要删除节点的地址
				j->next=j->next->next;//跨过要删除节点
				L->len--;
				free(t);
				t=NULL;
			}else{
				j=j->next;//当出现重复项时,j的地址位置不要移动,因为j->next已经更新,此时移动j,下次比较时,
 //j->next->data会跨过一个未比较的数据,避免多个重复项连续时,出现漏删
			}
		}
	}
}
17.排序-冒泡排序 
int bubble_sort_Link(PLink L){
	if(empty(L)){
		printf("冒泡排序失败\n");
		return -1;
	}
	int i,j,temp;
	PLink t;//用于遍历链表
	for(i=1;i<L->len;i++){
		t=L->next;//遍历一遍后,t指针重新赋值用于再次遍历
		for(j=0;j<L->len-i;j++){
			if(t->data>t->next->data){
				temp=t->data;
				t->data=t->next->data;
				t->next->data=temp;
			}
			t=t->next;//遍历链表
		}
	}
	
}
18.链表空间释放 
int free_link(PLink L){
	if(NULL==L){
		printf("链表创建失败\n");
		return -1;
	}
	/*int i;//销毁时不能用len做判断条件,因为L会释放掉,应该采用判空
	for(i=0;i<L->len+1;i++){//采用循环方式依次释放malloc开辟的动态空间,并指针依次置空
		PLink Q=L->next;
		free(L);
		L=NULL;
		L=Q;
	}*/
	PLink t=L;
	while(t!=NULL){
		t=t->next;
		free(L);
		L==NULL;
		L=t;
	}
	printf("销毁成功\n");
	return 0;		
}

分文件代码

main.c
#include "link.h"
int main(int argc, const char *argv[])
{
	int a[10]={1,2,3,4,7,7,8,8,8,10};
	//1.创建单链表
	PLink L=create();//创建头节点
#if 0
	//1.1头插法
	int i;
	for(i=0;i<10;i++){
		front_insert(L,a[i]);
	}
#endif
	//1.2尾插法
	for(int i=0;i<10;i++){
		rear_insert(L,a[i]);
	}
#if 0
	//2.遍历单链表
	output_link(L);
	//3.任意位置插入一个节点
	anypos_insert(L,4,15);
	output_link(L);
	//4.任意位置删除一个节点
	anypos_delete(L,2);
	output_link(L);
	//5.任意位置查找一个节点
	anypos_find(L,8);
	//6.任意位置修改一个节点
	anypos_change(L,7,999);
	output_link(L);
	//7.头删
	front_delete(L);
	output_link(L);
	//8.尾删
	rear_delete(L);
	output_link(L);
	//9.按值删除(删除所有相同的值)
	value_all_delete(L,7);
	output_link(L);
	//10.按值删除(删除最后相同的值)
	value_last_delete(L,8);
	output_link(L);
	//11.按值修改(修改最后相同的值)
	value_last_change(L,7,888);
	output_link(L);
	//12.按值查找返回地址(打印所有值相同的地址)
	value_all_find(L,8);
#endif
	//13.链表逆置
	reverse_link(L);
	output_link(L);
	//14.链表去重
	repeat_link(L);
	output_link(L);
	//15.链表排序(冒泡、插值排序-创建一个新链表去实现)
	bubble_sort_Link(L);
	output_link(L);
	//16.销毁
	free_link(L);
	L=NULL;//指针置空
	return 0;
}
link.c
#include "link.h"
PLink create(){//创建头节点
	PLink P=(PLink)malloc(sizeof(mylink));
	if(NULL==P){
		perror("create error");
		return NULL;
	}
	P->len=0;
	P->next=NULL;
	return P;//返回头节点地址
}
int front_insert(PLink L,int a){//头部插入元素
	if(NULL==L){
		printf("单链表不存在,创建失败\n");
		return -1;
	}
	PLink P=(PLink)malloc(sizeof(mylink));//申请新节点
	P->data=a;//数据域赋值
	P->next=L->next;//连线右边
	L->next=P;//连线左边//顺序不能颠倒
	L->len++;
	return 0;
}
int rear_insert(PLink L,int a){//尾部插入元素
	if(NULL==L){
		printf("单链表不存在,创建失败\n");
		return -1;
	}
	PLink t=L;
	for(int i=0;i<L->len;i++){//遍历单链表,找到尾,因为尾插是在最后节点后面即len+1位置插入
	                      	//,所以我们遍历len次,不是len-1次,找到len+1节点的前面节点
		t=t->next;
	}
	PLink P=(PLink)malloc(sizeof(mylink));//申请新节点
	P->data=a;//数据域赋值
	t->next=P;
	P->next=NULL;
	L->len++;
	return 0;
}
int output_link(PLink L){//遍历单链表
	int i;
	PLink t=L;
	for(i=0;i<L->len;i++){//遍历len次
		t=t->next;
		printf("%d\t",t->data);//打印数据域
	}
	printf("\n");
	return 0;
}
int anypos_insert(PLink L,int post,int key){
	if(NULL==L||post<1||post>L->len+1){
		printf("任意位置插入失败\n");
		return -1;
	}
	int i;
	PLink t=L;
	for(i=1;i<post;i++){//移动post-1次指向待插入节点的前驱
		t=t->next;
	}
	PLink P=(PLink)malloc(sizeof(mylink));//申请新节点
	P->data=key;//数据域赋值
	P->next=t->next;//指向右边
	t->next=P;//指向左边//顺序不能颠倒
	L->len++;//长度+1
	return 0;
}
int anypos_delete(PLink L,int post){
	if(NULL==L||post<1||post>L->len||L->len==0){
		printf("任意位置删除失败\n");
		return -1;
	}
	int i;
	PLink t=L;
	for(i=1;i<post;i++){//移动post-1次指向待删除节点的前驱
		t=t->next;
	}
	PLink Q=t->next;//保留要删除的节点地址
	t->next=t->next->next;//跨过要删除节点
	L->len--;//长度-1
	free(Q);//释放要删除的空间
	Q=NULL;//指针置空
    return 0;
}
int anypos_find(PLink L,int post){
	if(NULL==L||post<1||post>L->len){
		printf("任意位置查找失败\n");
		return -1;
	}
	int i;
	PLink t=L;
	for(i=0;i<post;i++){//移动post次后,t指向post节点
		t=t->next;
	}
	printf("找到了,该节点数据为:%d\n",t->data);
	return 0;
}
int anypos_change(PLink L,int post,int key){
	if(NULL==L||post<1||post>L->len){
		printf("任意位置修改失败\n");
		return -1;
	}
	int i;
	PLink t=L;
	for(i=0;i<post;i++){//移动post次后,t指向post节点
		t=t->next;
	}
	t->data=key;//修改post位置节点数据内容
	printf("修改成功\n");
	return 0;
}
int front_delete(PLink L){
	if(NULL==L||L->len==0){
		printf("头删失败\n");
		return -1;
	}
	PLink Q=L->next;//保留要删除的节点地址
	L->next=L->next->next;//跨国要删除的节点
	L->len--;//长度-1
	free(Q);//释放要删除节点空间
	Q=NULL;//释放后指向地址置空
	return 0;
}
int rear_delete(PLink L){
	if(NULL==L||L->len==0){
		printf("尾删失败\n");
		return -1;
	}
	PLink t=L;
	int i;
	for(i=1;i<L->len;i++){//执行len-1次找到尾节点的前一个节点
		t=t->next;
	}
	PLink Q=t->next;//保留尾节点的地址
	t->next=NULL;//尾节点删除
	L->len--;//长度-1
	free(Q);//释放尾节点空间
	Q=NULL;//指针置空
	return 0;
}
int value_all_delete(PLink L,int value){
	if(NULL==L||L->len==0){
		printf("按值删除失败\n");
		return -1;
	}
	PLink t=L;
	int i,sub=-1;
	for(i=0;i<L->len;i++){
		if(t->next->data==value){//按值删除所有相同的值
			PLink Q=t->next;//存储要删除节点地址
			t->next=t->next->next;//跨过要删除节点
			L->len--;//长度-1
			free(Q);//释放删除节点空间
			Q=NULL;//指针置空
			sub=0;
			i--;//多执行一次,避免漏删
			continue;//删除一个节点后,不让t指向下一个节点,避免前后节点数据值相同,t移动导致漏删!!!
		}
		t=t->next;//遍历链表
	}
	if(sub==-1){
		printf("链表中没有相同的值,删除失败\n");
		return -1;
	}
	return 0;
}
int empty(PLink L){
	if(NULL==L||L->len==0){
		return 1;
	}
	return 0;
}
int value_last_delete(PLink L,int value){
	if(empty(L)){
		printf("按值删除失败\n");
		return -1;
	}
	PLink t=L,Q;
	int i,sub=-1;
	for(i=0;i<L->len;i++){
		if(t->next->data==value){
			Q=t;//保留要删除最后节点前一个节点地址
			sub=0;
		}
		t=t->next;//遍历链表
	}
	if(sub==0){
		PLink W=Q->next;//保留要删除节点的地址
		Q->next=Q->next->next;//跨过要删除节点
		L->len--;//长度-1
		free(W);//释放要删除节点空间
		W=NULL;//指针置空
		return 0;
	}else{
		printf("链表中没有相同的值,删除失败\n");
		return -1;
	}
}
int value_last_change(PLink L,int key,int value){
	if(NULL==L){
		printf("按值修改失败\n");
		return -1;
	}
	PLink t=L,Q;
	int i,sub=-1;
	for(i=0;i<L->len;i++){
		t=t->next;//遍历链表
		if(t->data==key){
			Q=t;//保留要修改最后节点的地址
			sub=0;
		}
	}
	if(sub==0){
		Q->data=value;
		printf("修改成功\n");
		return 0;
	}else{
		printf("链表中没有相同的值,修改失败\n");
		return -1;
	}
}
int value_all_find(PLink L,int value){
	if(NULL==L){
		printf("按值查找失败\n");
		return -1;
	}
	PLink t=L;
	int i,sub=-1;
	for(i=0;i<L->len;i++){
		t=t->next;//遍历链表
		if(t->data==value){
			printf("找到了,地址为%p\n",t);
			sub=0;
		}
	}
	if(sub==-1){
		printf("链表中没有找到相同的值,查找失败\n");
	}
	return 0;
}
int reverse_link(PLink L){
	if(NULL==L){
		printf("逆序失败\n");
		return -1;
	}
/*  第一种逆序方式
    PLink temp=L->next;
	PLink next_node=L->next;//保留下一个节点的地址,避免丢失
	while(temp!=NULL){//temp与next_node错开一个节点,temp进行头插操作,实现逆序
	next_node=next_node->next;
	temp->next=L->next;
	L->next=temp;
	temp=next_node;
	}
	temp=L->next;//若开辟一个新的头节点且next初始化为NULL,则不需要下面操作
	for(int i=0;i<L->len;i++){
		temp=temp->next;	
	}
	temp->next=NULL;
	*/
	//第二种逆序方式
	PLink Q,t;
	Q=L->next;//指向第一个节点
	t=Q->next;//指向第二个节点
	while(t!=NULL){
		Q->next=t->next;//将1号和3号节点链接上
		t->next=L->next;//头插操作
		L->next=t;
		t=Q->next;//进行下一轮节点插入
	}
}
int repeat_link(PLink L){
	if(empty(L)){
		printf("链表去重失败\n");
		return-1;
	}
	/*第一种方式,i和j都是int,不是指针
	PLink Q=L,W;
	for(int i=0;i<L->len;i++){
		Q=Q->next;
		W=Q;//一轮循环下来,W应重新赋值指向Q的节点
		for(int j=i+1;j<L->len;j++){
			if(Q->data==W->next->data){
				PLink Z=W->next;
				W->next=W->next->next;
				L->len--;
				free(Z);
				Z=NULL;
				j--;//多执行一次避免漏删
				continue;//多个重复项连续存在时,避免漏删
			}
			W=W->next;
		}
	}*/
	//第二种方式,i和j都是指针,比第一种优化一些
	PLink i,j;
	for(i=L->next;i->next!=NULL;i=i->next){
		for(j=i;j->next!=NULL;){
			if(i->data==j->next->data){//注意删除是要j指向前一节点地址
				PLink t=j->next;//保留要删除节点的地址
				j->next=j->next->next;//跨过要删除节点
				L->len--;
				free(t);
				t=NULL;
			}else{
				j=j->next;//当出现重复项时,j的地址位置不要移动,因为j->next已经更新,此时移动j,下次比较时,
				              //j->next->data会跨过一个未比较的数据,避免多个重复项连续时,出现漏删
			}
		}
	}
}
int bubble_sort_Link(PLink L){
	if(empty(L)){
		printf("冒泡排序失败\n");
		return -1;
	}
	int i,j,temp;
	PLink t;//用于遍历链表
	for(i=1;i<L->len;i++){
		t=L->next;//遍历一遍后,t指针重新赋值用于再次遍历
		for(j=0;j<L->len-i;j++){
			if(t->data>t->next->data){
				temp=t->data;
				t->data=t->next->data;
				t->next->data=temp;
			}
			t=t->next;//遍历链表
		}
	}
	
}
int free_link(PLink L){
	if(NULL==L){
		printf("链表创建失败\n");
		return -1;
	}
	/*int i;//销毁时不能用len做判断条件,因为L会释放掉,应该采用判空
	for(i=0;i<L->len+1;i++){//采用循环方式依次释放malloc开辟的动态空间,并指针依次置空
		PLink Q=L->next;
		free(L);
		L=NULL;
		L=Q;
	}*/
	PLink t=L;
	while(t!=NULL){
		t=t->next;
		free(L);
		L==NULL;
		L=t;
	}
	printf("销毁成功\n");
	return 0;		
}
link.h 
#ifndef __LINK__
#define __LINK__
#include <myhead.h>
typedef struct stu{
	union{
		int len;//用于头节点,统计节点个数
		int data;//用于正常节点,存储数据
	};
	struct stu *next;//指针域
}mylink,*PLink;

//*******************
//函数申明
PLink create();
int front_insert(PLink,int);
int output_link(PLink L);
int rear_insert(PLink,int);
int insert(PLink,int,int);
int anypos_insert(PLink,int,int);
int anypos_delete(PLink,int);
int anypos_find(PLink,int);
int anypos_change(PLink,int,int);
int front_delete(PLink);
int rear_delete(PLink);
int empty(PLink);
int value_all_delete(PLink,int);
int value_last_delete(PLink,int);
int value_last_change(PLink,int,int);
int value_all_find(PLink,int);
int reverse_link(PLink);
int repeat_link(PLink);
int bubble_sort_Link(PLink);
int free_link(PLink);
#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值