单链表--c语言实现的带头结点的单链表

由于考研大部分单链表的实现方式中,“链表结构体”和“结点结构体”都是共用同一个结构,与之前的,表结构体和结点结构体分开方式的单链表,有很多地方的操作和初始化都略有不同,所以又抽空写了一版适合考研党参考的单链表。

 由于带头结点的单链表更方便,所以采用的是带头结点的方式,不带头节点的和这个差不多,推荐带头节点。代码并不完善,欢迎评论指出不足^0^

 完整代码如下:

 LinkedList.c

#define ElemType int
#include <stdlib.h>
#include <stdio.h>

typedef struct Node{		//单链表结构体,也是结点结构体
	ElemType data;			//数据域
	struct Node *next;		//指针域
}Node,*List;				//List为指向结构体Node的指针

// InitList(&L): 		初始化单链表
void InitList(List *list){
	//让链表指针指向,新创建的头节点
	(*list) = (Node*)malloc(sizeof(Node));
	//如果头节点创建失败,退出程序
	if( (*list) == NULL ){ exit(1); }
	//创建成功
	(*list)->data = 0;//头节点数据域设置为0,也就是表长为0
	(*list)->next = NULL;//头结点next置空
}

// DestroyList(&L): 	销毁单链表
void DestroyList(List* list){
	//已经被销毁,或还未初始化,什么也不做
	if( (*list) == NULL){ return; }
	// 空表,将头节点删除
	if( (*list)->data == 0){
		free(*list);
		(*list) = NULL;
		printf("删除头结点\n");
	}else{//非空表,层层删除链表结点
		//临时Node类型指针t,指向首元结点
		Node* t = (*list)->next;
		while( t!=NULL ){
			t = t->next;
			free( (*list)->next );
			(*list)->next = t;
			printf("删除1个结点\n");
		}
		//链表结点删除完毕,删除头结点
		free(*list);
		printf("删除头节点\n");
		//表指针置空
		(*list) = NULL;
	}
}

// ListEmpty(L):  		判断单链表是否为空
int ListEmpty(List list){
	return list->next == NULL;
}

// ClearList(&L): 		清空线性表
void ClearList(List* list){
	DestroyList(list);
}

//获取表长
int GetSize(List list){
	return list->data;
}

//获取链表上第i个结点的指针,没有返回NULL
Node* GetNode(List list, int i){
	Node *ret = NULL;
	if( i>(list->data) || i<1 ){		//下标非法
	}else if( i==1 ){					//首元结点
		ret = list->next;
	}else{								//表中间的结点
		//临时指针t,指向首元结点
		Node* t = list->next;
		int j;
		for( j=1; j<i; j++ ){
			t = t->next;
		}
		ret = t;
	}
	return ret;
}

// 表头插入元素e
void InsertHead(List list, ElemType e){
	// 新建node
	Node* newNode = (Node*)malloc(sizeof(Node));
	newNode->data = e;
	newNode->next = list->next;
	// 更改首元结点
	list->next = newNode;
	list->data ++;
}

// 删除首元结点
void DeleteHead(List list){
	// 若为空表,什么也不做
	if(list->data == 0){
	}else{//表非空,进行删除
		//临时指针指向首元结点的下一个结点
		Node* t = list->next->next;
		free(list->next);
		printf("删除首元结点\n");
		list->data --;
		list->next = t;
	}
}

// ListInsert(&L,i,e): 	链表的第i个位置上插入元素e
void ListInsert(List list, int i, ElemType e){
	if( i<1 || i>(list->data)+1 ){		//下标非法,异常退出
		exit(1);
	}else{
		if( i==1 ){						//表头插入
			InsertHead(list, e);
		}else{							//表内插入
			//创建新节点newNode
			Node* newNode = (Node*)malloc(sizeof(Node));
			newNode->data = e;
			//临时指针指向首元结点
			Node* t = list->next;
			//循环找到第i-1个结点,在其后进行插入
			int j;
			for(j=2; j<i; j++){
				t = t->next;
			}
			//此时t指向要插入位置的前面
			newNode->next = t->next;
			t->next = newNode;
			list->data ++;
		}
	}
}

// ListDelete(&L,i): 	删除链表上第i元素并返回其值
ElemType ListDelete(List list, int i){
	// 先判断下标是否越界
	if(i<1 || i>list->data){ exit(1); }

	ElemType ret;
	if(i == 1){					//删表头
		ret = list->next->data;
		DeleteHead(list);
	}else{						//删表中间
		//拿到第i-1个Node
		Node* prior = GetNode(list, i-1);
		//保存返回值
		ret = prior->next->data;
		//临时指针t保存要删除的结点地址
		Node* t = prior->next;
		//更改第i-1个Node的next指针域
		prior->next = prior->next->next;
		//删除结点
		free(t);
		printf("删除第%d个结点\n", i);
		list->data --;
	}
	return ret;
}

// GetElem(L,i,&e):  	获取L表中第i个元素
ElemType GetElem(List list, int i){
	return GetNode(list, i)->data;
}

//LocateElem(L,e):定位表中的元素e,看它是第几个元素,失败返回-1
int LocateElem(List list, ElemType e){
	int ret = -1;
	//临时指针t指向首元结点
	Node* t = list->next;
	int i;
	for(i=1; i<=list->data; i++){
		if(t->data == e){//找到了,结束循环返回下标
			ret = i;
			break;
		}else{
			t = t->next;//没找到,指针后移继续找
		}
	}
	return ret;
}

//遍历链表
void TraverseList(List list){
	//临时Node指针指向首元结点
	Node* t = list->next;
	printf("\n");
	while(t != NULL){
		printf("%d  ", t->data);
		t = t->next;
	}
	printf("\n");
}

//=============测试程序==============================================================

int main(int argc, char const *argv[])
{
	// 定义一个单链表并初始化
	List list = NULL;
	InitList(&list);

	// 添加元素
	InsertHead(list, 13);
	InsertHead(list, 23);
	InsertHead(list, 33);
	InsertHead(list, 43);
	InsertHead(list, 53);
	TraverseList(list);

	printf("第2个元素为:%d\n", GetElem(list, 2));
	printf("元素33是表中第%d个\n", LocateElem(list, 33));

	ListInsert(list, 3, 333);
	TraverseList(list);

	ListDelete(list, 3);
	printf("\n链表是否为空:%d\n", ListEmpty(list));
	DeleteHead(list);
	TraverseList(list);
	printf("表长为:%d\n", GetSize(list));
	TraverseList(list);

	// 最后一定要销毁链表
	DestroyList(&list);
	return 0;
}

 运行结果

这种实现方式的单链表,在初始化和销毁时需要用到二重指针,也可以按照以上方式,在结构体声明里使用别名,屏蔽掉二重指针来当作普通指针来使用;注意内存释放后要将链表指针置空,因为可能存在误用。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值