二:单链表的实现(附带运行截图,亲测有效)

一:结点的定义:

#include<stdio.h>
#include<stdlib.h>
typedef  int ElemType;
typedef struct LNode {//定义一个结点结构
	ElemType data;//数据域
	struct LNode* next;//指针域,next是下一个结点的地址
}LNode,*LinkList;

(1)注意: LNode *相当于LinkList

(2)搞清楚带头结点和不带头结点的区别(下面按顺序分别是带头结点链表,不带头结点单链表)

二:单链表的初始化(带头结点)

bool HaveHead_InitList(LinkList& L) {
	L = (LNode*)malloc(sizeof(LNode));//创建一个头结点,并为该头结点开辟一个结点所需要的空间(所以后面要是要加新结点,则需要另辟结点空间)
	if (L == NULL)   return false;//即:如果空间分配失败
	L->next = NULL;
	return true;
}

三:单链表的初始化(不带头结点)

bool NoHead_InitList(LinkList& L) {
	L== NULL;//即空表,需要特别初始化为空   是因为:防止L在没有赋值的情况下携带脏数据而影响后序操作
	return true;
}

四:判空(带头结点)

bool HaveHead_Empty(LinkList L) {
	if (L->next == NULL) //不带头结点则是  if(L==NULL)  return true;  else   return false;
		return true;
	else return false;
}

五:判空(不带头结点)

bool HaveHead_Empty(LinkList L) {
	  if(L==NULL)  return true;  
	else return false;
}

六:建单链表----头插法(带头结点)

//建单链表----头插法(逆向建立单链表)(带头结点)
LinkList Havehead_List_HeadInsert(LinkList& L) {
	L = (LinkList)malloc(sizeof(LNode));     //建立头结点 
	L->next = NULL; //初始尾空链表 (必须初始化) 
	LNode* s;
	int x;
	scanf("%d", &x);
	while (x != -1) {
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;              //即头结点指向新的结点 
		scanf("%d", &x);
	}
	return L;
}

七:建单链表----头插法(不带头结点)

//建单链表----头插法(逆向建立单链表)(不带头结点)
LinkList  Nohead_List_HeadInsert(LinkList& L){
	LNode* s;  //声明一个临时结点
	int x;
	L = NULL;
	scanf("%d", &x);  //输入结点的值
	while (x != -1){
		s = (LNode*)malloc(sizeof(LNode));  //创建新结点
		s->data = x;
		if (L == NULL) { // 若第一次创建节点,则将该点设置为头结点
			L = s;
			s->next = NULL;
		}else {                   // 若不是第一次创建节点,则直接将新节点接到链表头
			s->next = L;
			L = s;
		}
		scanf("%d", &x);
	}
	return L;
}

八:建单链表----尾插法(带头结点)

//建单链表----尾插法(正向建立单链表)(带头结点)
 LinkList Havehead_List_TailInsert1(LinkList &L){  //采用带有头结点的尾插法正向建立单链表
	 int x;
	 L = (LinkList)malloc(sizeof(LNode));  //创建头结点
	 LNode* s;
	 LNode *r=L;  //s为临时结点,r为表尾指针
	scanf("%d", &x);  //输入结点的值
	while (x != -1){
		s = (LNode*)malloc(sizeof(LNode));  //创建新结点
		s->data = x;
		r->next = s;
		r = s;  //r指向新的表尾结点
		scanf("%d", &x);
	}
	r->next = NULL;      //尾结点指针置空
	return L;
}

九:建单链表----尾插法(不带头结点)

//建单链表----尾插法(正向建立单链表)(不带头结点)
 LinkList Nohead_List_TailInsert(LinkList& L)  //采用不带有头结点的尾插法正向建立单链表
 {
	 int x;
	 LNode* s;
	 LNode* r = L=NULL;  //s为临时结点,r为表尾指针
	 scanf("%d", &x);  //输入结点的值
	 while (x != -1) {
		 s = (LNode*)malloc(sizeof(LNode));  //创建新结点
		 s->data = x;
		 if (L == NULL){  // 创建链表的第一个节点
			 L = s;
			 r = s;
			 s->next = NULL;
		 } else {
			 r->next = s;
			 r = s;
		 }
		 scanf("%d", &x);
	 }
	 r->next = NULL;  //尾结点指针为空
	 return L;
 }

十:按位查找,返回第i位的地址(带头结点)

//按位查找,返回第i位的地址(带头结点)
LNode* Head_GetElem(LinkList L, int i) {
	if (i < 1)  return NULL;  //位置是第负数个的结点不存在
	LNode* p = L->next;               //因为头结点不保存数据,数据从头结点的下一个结点才开始保存
	int j = 0;//因为指针的值的是下一个结点的地址,所以注意这里不是int j=1;
	while (p != NULL && j < i) {//即当j=i的时候跳出循环
		p = p->next;
		j++;
	}
	return p;
}

十一:按位查找,返回第i位的地址(不带头结点)

//按位查找(不带头结点),返回第i位的地址
LNode* NoHead_GetElem(LinkList L, int i) {
	if (L == NULL || i <= 0) {
		return NULL;
	}
	LNode* p = L;
	int j = 0;//因为指针的值的是下一个结点的地址,所以注意这里不是int j=1;
	while (p != NULL && j < i) {
		p = p->next;
		j++;
	}
	return p;
}

十二:按位序插入(带头结点)

//按位序插入(带头结点)
bool Havehead_ListInsert(LinkList& L, int i, ElemType e) {//即插入在第几个,插入的元素是i
	if (i < 1)  return false;
	/*如果是不带头结点的话,,则如果删除或插在第一个位置(这里是插入的情况下),需要更改头指针L,即加上下面的判断
	if (i==1){
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = e;
		s->next = L;
		L= s;
		return true;
	}
	*/
	LNode* p = L;
	int j = 0;//表示当前p指向的是第几个结点,如果是不带头结点的话,则是  int j=1;
	while (p != NULL && j < i - 1) {
		p = p->next;
		j++;
	}
}

十三:按位序插入(不带头结点)

//按位序插入(不带头结点)
//即插入在第几个,插入的元素是i
bool Nohead_ListInsert(LinkList & L, int i, ElemType e) {
	if (i < 1)  return false;
	if (i == 1) {
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = e;
		s->next = L;
		L = s;
		return true;
	}
	LNode* p = L;
	int j = 1;
	while (p != NULL && j < i - 1) {
		p = p->next;
		j++;
	}
}

十四:按位序删除(带头结点)

//按位序删除(带头结点)
bool HaveHead_ListDelete(LinkList& L, int i) {
	if (i < 1)    return false;
	LNode* p;                    //指针p指向当前扫描到的节点
	p = L;                           //令L指向头节点,头节点是第0个节点(不存数据)
	int j = 0;                   // 当前p指向的是第几个节点
	while (p != NULL && j < i - 1) {     //循环到第i-1个节点 
		p = p->next;
		j++;
	}
	if (p == NULL) return false;   //前面和插入操作差不多
	if (p->next == NULL) return false;          //第i-1个节点之后没有其他节点 
	LNode* q = p->next;                       //q指向被删除的节点 
	p->next = q->next;
	free(q);
	return true;
}

十五:按位序删除(不带头结点)

//按位序删除(不带头结点)
bool NoHead_ListDelete(LinkList& L, int i) {
	if (i < 1) {
		return false;
	}
	if (i == 1) {
		LNode* q = L;		// 头指针L指向链表第一个结点,声明一个指针变量q用来存储链表的第一个结点
		L = q->next;		//让头指针L指向链表的第二个结点
		free(q);		// 释放q结点,头指针L又指向原链表的第二个结点,那么就表示q结点被删了
	}
	LNode* p=L;
	int j = 0;
	while (p != NULL && j < i - 1) {
		p = p->next;
		j++;
	}
	if (p = NULL) {
		return false;
	}
	LNode* q = p->next;
	p->next = q->next;
	free(q);
	return true;
}

十六:求表长

int Length(LinkList  L) {//不带头结点的单链表操作中, //除了初始化InitList(),判空isEmpty(),按位查找GetElem(),插入ListInsert(),删除ListDelete()操作与带头结点的单链表有差别外,其它的操作基本上一样。
	int len = 0;                 
	LNode* p = L;//定义一个结点指向第一个结点
	while (p->next != NULL) {
		p = p->next;
		len++;
	}
	return len;
}

十七:基本测试代码

int main() {
	LinkList L;
	printf("下面先展示带头结点的单链表基本操作测试");

	printf("利用头插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
	L = Havehead_List_HeadInsert(L);
	HaveHead_PrintList(L);

	printf("利用尾插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
	L = Havehead_List_TailInsert1(L);
	HaveHead_PrintList(L);

	printf("在第1个位置插入元素11后:\n");
	Havehead_ListInsert(L, 1, 11);
	HaveHead_PrintList(L);

	printf("删除第一个元素后:\n");
	HaveHead_ListDelete(L, 1);
	HaveHead_PrintList(L);

	printf("查找第一个元素:\n");
	Head_GetElem(L, 1);
	HaveHead_PrintList(L);

	int len = Length(L);
	printf("表长 = %d\n",len);
	


	printf("\n***************************************************************************************************************************\n");
	printf("下面展示不带头结点的单链表基本操作测试");
	printf("利用头插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
	L = Nohead_List_HeadInsert(L);
	NoHead_PrintList(L);

	printf("利用尾插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
	L = Nohead_List_TailInsert(L);
	NoHead_PrintList(L);

	printf("在第1个位置插入元素11后:\n");
	Nohead_ListInsert(L, 1, 11);
	NoHead_PrintList(L);

	printf("删除第一个元素后:\n");
	NoHead_ListDelete(L, 1);
	NoHead_PrintList(L);

	printf("查找第一个元素:\n");
	NoHead_GetElem(L, 1);
	NoHead_PrintList(L);

	return 0;
}

十八:运行截图

十九:完整代码

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef  int ElemType;
typedef struct LNode {//定义一个结点结构
	ElemType data;//数据域
	struct LNode* next;//指针域,next是下一个结点的地址
}LNode,*LinkList;

//初始化(带头结点)
bool HaveHead_InitList(LinkList& L) {
	L = (LNode*)malloc(sizeof(LNode));//创建一个头结点,并为该头结点开辟一个结点所需要的空间(所以后面要是要加新结点,则需要另辟结点空间)
	if (L == NULL)   return false;//即:如果空间分配失败
	L->next = NULL;
	return true;
}

//初始化(不带头结点)
bool NoHead_InitList(LinkList& L) {
	L== NULL;//即空表,需要特别初始化为空   是因为:防止L在没有赋值的情况下携带脏数据而影响后序操作
	return true;
}

//判空(带头结点)
bool HaveHead_Empty(LinkList L) {
	if (L->next == NULL) //不带头结点则是  if(L==NULL)  return true;  else   return false;
		return true;
	else return false;
}

//建单链表----头插法(逆向建立单链表)(带头结点)
LinkList Havehead_List_HeadInsert(LinkList& L) {
	L = (LinkList)malloc(sizeof(LNode));     //建立头结点 
	L->next = NULL; //初始尾空链表 (必须初始化) 
	LNode* s;
	int x;
	scanf("%d", &x);
	while (x != -1) {
		s = (LNode*)malloc(sizeof(LNode));
		s->data = x;
		s->next = L->next;
		L->next = s;              //即头结点指向新的结点 
		scanf("%d", &x);
	}
	return L;
}

//建单链表----头插法(逆向建立单链表)(不带头结点)
LinkList  Nohead_List_HeadInsert(LinkList& L){
	LNode* s;  //声明一个临时结点
	int x;
	L = NULL;
	scanf("%d", &x);  //输入结点的值
	while (x != -1){
		s = (LNode*)malloc(sizeof(LNode));  //创建新结点
		s->data = x;
		if (L == NULL) { // 若第一次创建节点,则将该点设置为头结点
			L = s;
			s->next = NULL;
		}else {                   // 若不是第一次创建节点,则直接将新节点接到链表头
			s->next = L;
			L = s;
		}
		scanf("%d", &x);
	}
	return L;
}

//建单链表----尾插法(正向建立单链表)(带头结点)
 LinkList Havehead_List_TailInsert1(LinkList &L){  //采用带有头结点的尾插法正向建立单链表
	 int x;
	 L = (LinkList)malloc(sizeof(LNode));  //创建头结点
	 LNode* s;
	 LNode *r=L;  //s为临时结点,r为表尾指针
	scanf("%d", &x);  //输入结点的值
	while (x != -1){
		s = (LNode*)malloc(sizeof(LNode));  //创建新结点
		s->data = x;
		r->next = s;
		r = s;  //r指向新的表尾结点
		scanf("%d", &x);
	}
	r->next = NULL;      //尾结点指针置空
	return L;
}

//建单链表----尾插法(正向建立单链表)(不带头结点)
 LinkList Nohead_List_TailInsert(LinkList& L)  //采用不带有头结点的尾插法正向建立单链表
 {
	 int x;
	 LNode* s;
	 LNode* r = L=NULL;  //s为临时结点,r为表尾指针
	 scanf("%d", &x);  //输入结点的值
	 while (x != -1) {
		 s = (LNode*)malloc(sizeof(LNode));  //创建新结点
		 s->data = x;
		 if (L == NULL){  // 创建链表的第一个节点
			 L = s;
			 r = s;
			 s->next = NULL;
		 } else {
			 r->next = s;
			 r = s;
		 }
		 scanf("%d", &x);
	 }
	 r->next = NULL;  //尾结点指针为空
	 return L;
 }

//按位查找,返回第i位的地址(带头结点)
LNode* Head_GetElem(LinkList L, int i) {
	if (i < 1)  return NULL;  //位置是第负数个的结点不存在
	LNode* p = L->next;               //因为头结点不保存数据,数据从头结点的下一个结点才开始保存
	int j = 0;//因为指针的值的是下一个结点的地址,所以注意这里不是int j=1;
	while (p != NULL && j < i) {//即当j=i的时候跳出循环
		p = p->next;
		j++;
	}
	return p;
}

//按位查找(不带头结点),返回第i位的地址
LNode* NoHead_GetElem(LinkList L, int i) {
	if (L == NULL || i <= 0) {
		return NULL;
	}
	LNode* p = L;
	int j = 0;//因为指针的值的是下一个结点的地址,所以注意这里不是int j=1;
	while (p != NULL && j < i) {
		p = p->next;
		j++;
	}
	return p;
}

//按位序插入(带头结点)
bool Havehead_ListInsert(LinkList& L, int i, ElemType e) {//即插入在第几个,插入的元素是i
	if (i < 1)  return false;
	/*如果是不带头结点的话,,则如果删除或插在第一个位置(这里是插入的情况下),需要更改头指针L,即加上下面的判断
	if (i==1){
		LNode* s = (LNode*)malloc(sizeof(LNode));
		s->data = e;
		s->next = L;
		L= s;
		return true;
	}
	*/
	LNode* p = L;
	int j = 0;//表示当前p指向的是第几个结点,如果是不带头结点的话,则是  int j=1;
	while (p != NULL && j < i - 1) {
		p = p->next;
		j++;
	}
}

	//按位序插入(不带头结点)
	//即插入在第几个,插入的元素是i
	bool Nohead_ListInsert(LinkList & L, int i, ElemType e) {
		if (i < 1)  return false;
		if (i == 1) {
			LNode* s = (LNode*)malloc(sizeof(LNode));
			s->data = e;
			s->next = L;
			L = s;
			return true;
		}
		LNode* p = L;
		int j = 1;
		while (p != NULL && j < i - 1) {
			p = p->next;
			j++;
		}
	}

	//按位序删除(带头结点)
	bool HaveHead_ListDelete(LinkList& L, int i) {
		if (i < 1)    return false;
		LNode* p;                    //指针p指向当前扫描到的节点
		p = L;                           //令L指向头节点,头节点是第0个节点(不存数据)
		int j = 0;                   // 当前p指向的是第几个节点
		while (p != NULL && j < i - 1) {     //循环到第i-1个节点 
			p = p->next;
			j++;
		}
		if (p == NULL) return false;   //前面和插入操作差不多
		if (p->next == NULL) return false;          //第i-1个节点之后没有其他节点 
		LNode* q = p->next;                       //q指向被删除的节点 
		p->next = q->next;
		free(q);
		return true;
	}


	//按位序删除(不带头结点)
	bool NoHead_ListDelete(LinkList& L, int i) {
		if (i < 1) {
			return false;
		}
		if (i == 1) {
			LNode* q = L;		// 头指针L指向链表第一个结点,声明一个指针变量q用来存储链表的第一个结点
			L = q->next;		//让头指针L指向链表的第二个结点
			free(q);		// 释放q结点,头指针L又指向原链表的第二个结点,那么就表示q结点被删了
		}
		LNode* p=L;
		int j = 0;
		while (p != NULL && j < i - 1) {
			p = p->next;
			j++;
		}
		if (p = NULL) {
			return false;
		}
		LNode* q = p->next;
		p->next = q->next;
		free(q);
		return true;
	}


//求表长
int Length(LinkList  L) {//不带头结点的单链表操作中, //除了初始化InitList(),判空isEmpty(),按位查找GetElem(),插入ListInsert(),删除ListDelete()操作与带头结点的单链表有差别外,其它的操作基本上一样。
	int len = 0;                 
	LNode* p = L;//定义一个结点指向第一个结点
	while (p->next != NULL) {
		p = p->next;
		len++;
	}
	return len;
}

//带头结点的打印
void HaveHead_PrintList(LinkList L)
{

	LinkList p;
	p = L->next;
	printf("链表元素如下:\n");
	while (p != NULL)
	{

		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}

//不带头结点的打印
void NoHead_PrintList(LinkList L)
{

	LinkList p;
	p = L;
	printf("链表元素如下:\n");
	while (p != NULL)
	{

		printf("%d ", p->data);
		p = p->next;
	}
	printf("\n");
}


int main() {
	LinkList L;
	printf("下面先展示带头结点的单链表基本操作测试");

	printf("利用头插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
	L = Havehead_List_HeadInsert(L);
	HaveHead_PrintList(L);

	printf("利用尾插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
	L = Havehead_List_TailInsert1(L);
	HaveHead_PrintList(L);

	printf("在第1个位置插入元素11后:\n");
	Havehead_ListInsert(L, 1, 11);
	HaveHead_PrintList(L);

	printf("删除第一个元素后:\n");
	HaveHead_ListDelete(L, 1);
	HaveHead_PrintList(L);

	printf("查找第一个元素:\n");
	Head_GetElem(L, 1);
	HaveHead_PrintList(L);

	int len = Length(L);
	printf("表长 = %d\n",len);
	


	printf("\n***************************************************************************************************************************\n");
	printf("下面展示不带头结点的单链表基本操作测试");
	printf("利用头插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
	L = Nohead_List_HeadInsert(L);
	NoHead_PrintList(L);

	printf("利用尾插法建立单链表,请输入一系列值最后以-1结束,例如请输入 21 32 6 30 15 89 43 -1:\n");
	L = Nohead_List_TailInsert(L);
	NoHead_PrintList(L);

	printf("在第1个位置插入元素11后:\n");
	Nohead_ListInsert(L, 1, 11);
	NoHead_PrintList(L);

	printf("删除第一个元素后:\n");
	NoHead_ListDelete(L, 1);
	NoHead_PrintList(L);

	printf("查找第一个元素:\n");
	NoHead_GetElem(L, 1);
	NoHead_PrintList(L);

	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值