2.2单链表

单链表

n个结点链结成一个链表。每个结点由数据域和指针域两部分组成,单链表是只含一个指针域的链表。

特点:顺序存储

基本操作的实现

单链表的初始化:

构造一个如图的空表        

 

(1)生成新节点作为头节点,用头指针L指向头节点;

(2)头节点的指针域置空。

LinkList initLinkList() {
	NodePtr tempHeader = (NodePtr)malloc (sizeof(LNode));
	tempHeader->data = '\0';
	tempHeader->next = NULL;//将tempHeader的next域置空,赋一个空值  
	return tempHeader;
}

判断链表是否为空:

思路:判断头节点指针域是否为空

空表:链表中无元素,称为空链表(头指针和头结点仍然存在)

void ListEmpty(NodePtr paraHeader) {
	if(paraHeader->next)
		printf("The list is not empty.\n");
	else
		printf("The list is empty.\n");
}

 单链表的销毁:

思路:从头指针开始,依次释放所有节点(销毁后链表不存在)

LinkList DestroyList(NodePtr paraHeader) {
	NodePtr p;
	while(paraHeader != NULL) {
		p = paraHeader;
		paraHeader = paraHeader->next;
		free(p);
	}
}

清空链表: 

链表仍存在 ,但链表中无元素,成为空链表(头指针和头结点仍存在)

思路:依次释放所有节点,并将指针域设置为空

LinkList ClearList(NodePtr paraHeader) {
	NodePtr p, q;
	p = paraHeader->next;
	while(p!=NULL) {
		q = q->next;
		free(p);
		p = q;
	}
	paraHeader->next = NULL;//头节点指针域为空
}

求单链表的表长:

思路:从首元节点开始,依次计数所有结点

void lengthList(NodePtr paraHeader) {
	NodePtr p = paraHeader->next;//p指向第一个节点
	int i = 0;
	while (p != NULL) {
		i ++;
		p = p->next;//p指向下一节点
	}
	printf("The length of list is:%d\r\n",i);
}

 单链表的取值:

1.从第一个节点(L->next)顺链扫描,用指针p指向当前扫描到的节点,p初值p = L->next
2.j做计数器,累计当前扫描过的节点数,j初值为1
3.当p指向扫描到的下一节点时,计数器j加1
4.当j == i时,p所指的节点就是要找的第i个节点

LinkList GetElemList(NodePtr paraHeader, int i, char e) {
	//获取线性表中某个元素,通过变量e返回
	NodePtr p = paraHeader->next;//初始化,p指向首元节点,j赋值1
	int j = 1;
	while(p&&j<i) {//向后扫描,直到p指向地i个元素或p为空
		p = p->next;
		j ++;
	}
	if(!p||j>i)
		printf("第%d个元素不存在\n", i); //第i个元素不存在
	else
		e = p->data;//取第i个元素
		printf("第%d个元素:%c\n", i, e);
}

单链表的查找:

按值查找——根据指定数据获取该数据所在位置(地址)

1.从第一个节点起,依次和e相比较

2.如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”或地址

3.如果查遍整个链表都没有找到其值和e相等的元素,则输出"ERROR"

void LocateELemList(NodePtr paraHeader, char paraChar) {
	NodePtr p = paraHeader->next;
	int j = 1;
	while(p&&p->data!=paraChar) {
		p = p->next;
		j ++;
	}
	if(p)
		printf("%c的位置序号为:%d\n", paraChar, j);
	else
		printf("ERROR\n");
}

打印链表:

void printList(NodePtr paraHeader) {//NodePtr--指针类型,定义头指针paraHeader,因此paraHeader前不需要加*
	NodePtr p = paraHeader->next;//p指向首元节点
	while (p != NULL) {
		printf("%c",p->data);
		p = p->next;//p指向下一节点
	}
	printf("\r\n");
}

 头插法:

1.从一个空表开始,重复读入数据

2.生成新节点,将读入数据存放到新节点的数据域中

3.从最后一个节点开始,依次将各节点插入到链表的前端

 

void Createalist(NodePtr tempHeader, int n) {
	tempHeader = (NodePtr)malloc (sizeof(LNode));
	tempHeader->next = NULL;
	for(int i = 0; i < n; i ++) {
		NodePtr p = (NodePtr)malloc (sizeof(LNode));
		scanf("%c", &p->data);
		p->next = tempHeader->next;  
		tempHeader->next = p;
	}
}

 尾插法:

void appendElement(NodePtr paraHeader, char paraChar) {
	NodePtr p, q;
	
	q = (NodePtr)malloc(sizeof(LNode));
	q->data = paraChar;//将节点*q的数据域置为paraChar
	q->next = NULL;//将p的next域置空,赋一个空值 
	
	p = paraHeader;//p指向头节点
	while(p->next != NULL) {
		p = p->next;//p指向下一节点
	}
	
	p->next = q;//将节点*p的指针域指向节点*q
}

 给定位置插入元素:

void insertElement(NodePtr paraHeader, char paraChar, int paraPosition) {
	//paraChar给定字符  paraPosition给定位置
	NodePtr p, q;
	
	p = paraHeader;
	for(int i = 0; i < paraPosition; i ++) {
		p = p->next;
		if(p == NULL) {
			printf("The position %d is beyond the scope of the list.",paraPosition);
			return;
		}
	}
	
	q = (NodePtr)malloc(sizeof(LNode));
	q->data = paraChar;
	
	printf("linking\r\n");
	q->next = p->next;//将节点*q的指针域指向第i个节点
	p->next = q;
}

 从列表中删除元素:

void deleteElement(NodePtr paraHeader, char paraChar) {
	NodePtr p, q;
	p = paraHeader;
	while((p->next != NULL) && (p->next->data != paraChar)) {
		p = p->next;
	}
	
	if(p->next == NULL) {
		printf("Cannot dalete %c\r\n", paraChar);
		return;
	}
	
	q = p->next;
	p->next = p->next->next;
	free(q);//释放删除节点的空间
}

总代码:

 

#include<stdio.h>
#include<malloc.h>

//typedef重命名结构类型为LNode
typedef struct LinkNode {//声明结点的类型和指向节点的指针类型
	char data;//节点的数据域
	struct LinkNode *next;//节点的指针域
} LNode, *LinkList, *NodePtr;//节点,链表指针,节点指针   LinkList为指向结构体Lnode的指针类型

//单链表的初始化
LinkList initLinkList() {
	NodePtr tempHeader = (NodePtr)malloc (sizeof(LNode));
	tempHeader->data = '\0';
	tempHeader->next = NULL;//将tempHeader的next域置空,赋一个空值  
	return tempHeader;
}

//判断链表是否为空     
void ListEmpty(NodePtr paraHeader) {
	if(paraHeader->next)
		printf("The list is not empty\n");
	else
		printf("The list is empty\n");
}

//单链表的销毁
LinkList DestroyList(NodePtr paraHeader) {
	NodePtr p;
	while(paraHeader != NULL) {
		p = paraHeader;
		paraHeader = paraHeader->next;
		free(p);
	}
}

//清空链表
LinkList ClearList(NodePtr paraHeader) {
	NodePtr p, q;
	p = paraHeader->next;
	while(p!=NULL) {
		q = q->next;
		free(p);
		p = q;
	}
	paraHeader->next = NULL;//头节点指针域为空
}

//求单链表的表长
void lengthList(NodePtr paraHeader) {
	NodePtr p = paraHeader->next;
	int i = 0;
	while (p != NULL) {
		i ++;
		p = p->next;//p指向下一节点
	}
	printf("The length of list is:%d\r\n",i);
}

//单链表的取值
LinkList GetElemList(NodePtr paraHeader, int i, char e) {
	//获取线性表中某个元素,通过变量e返回
	NodePtr p = paraHeader->next;//初始化,p指向首元节点,j赋值1
	int j = 1;
	while(p&&j<i) {//向后扫描,直到p指向地i个元素或p为空
		p = p->next;
		j ++;
	}
	if(!p||j>i)
		printf("第%d个元素不存在\n", i); //第i个元素不存在
	else
		e = p->data;//取第i个元素
		printf("第%d个元素:%c\n", i, e);
}

//单链表的查找
void LocateELemList(NodePtr paraHeader, char paraChar) {
	NodePtr p = paraHeader->next;
	int j = 1;
	while(p&&p->data!=paraChar) {
		p = p->next;
		j ++;
	}
	if(p)
		printf("%c的位置序号为:%d\n", paraChar, j);
	else
		printf("ERROR\n");
}


//打印链表
void printList(NodePtr paraHeader) {//NodePtr--指针类型,定义头指针paraHeader,因此paraHeader前不需要加*
	NodePtr p = paraHeader->next;//p指向首元节点
	while (p != NULL) {
		printf("%c",p->data);
		p = p->next;//p指向下一节点
	}
	printf("\r\n");
}

//头插法
void Createalist(NodePtr tempHeader, int n) {
	tempHeader = (NodePtr)malloc (sizeof(LNode));
	tempHeader->next = NULL;
	for(int i = 0; i < n; i ++) {
		NodePtr p = (NodePtr)malloc (sizeof(LNode));
		scanf("%c", &p->data);
		p->next = tempHeader->next;  
		tempHeader->next = p;
	}
}

//尾插法
void appendElement(NodePtr paraHeader, char paraChar) {
	NodePtr p, q;
	
	q = (NodePtr)malloc(sizeof(LNode));
	q->data = paraChar;//将节点*q的数据域置为paraChar
	q->next = NULL;//将p的next域置空,赋一个空值 
	
	p = paraHeader;//p指向头节点
	while(p->next != NULL) {
		p = p->next;//p指向下一节点
	}
	
	p->next = q;//将节点*p的指针域指向节点*q
}

//给定位置插入元素
void insertElement(NodePtr paraHeader, char paraChar, int paraPosition) {
	//paraChar给定字符  paraPosition给定位置
	NodePtr p, q;
	
	p = paraHeader;
	for(int i = 0; i < paraPosition; i ++) {
		p = p->next;
		if(p == NULL) {
			printf("The position %d is beyond the scope of the list.",paraPosition);
			return;
		}
	}
	
	q = (NodePtr)malloc(sizeof(LNode));
	q->data = paraChar;
	
	printf("linking\r\n");
	q->next = p->next;//将节点*q的指针域指向第i个节点
	p->next = q;
}

//从列表中删除元素
void deleteElement(NodePtr paraHeader, char paraChar) {
	NodePtr p, q;
	p = paraHeader;
	while((p->next != NULL) && (p->next->data != paraChar)) {
		p = p->next;
	}
	
	if(p->next == NULL) {
		printf("Cannot dalete %c\r\n", paraChar);
		return;
	}
	
	q = p->next;
	p->next = p->next->next;
	free(q);//释放删除节点的空间
}

void appendInsertDeleteTest() {
	LinkList tempList = initLinkList();
	printList(tempList);
	ListEmpty(tempList);

	lengthList(tempList);
	ClearList(tempList);

	appendElement(tempList,'H');
	appendElement(tempList,'e');
	appendElement(tempList,'l');
	appendElement(tempList,'l');
	appendElement(tempList,'o');
	appendElement(tempList,'!');
	printList(tempList);

	deleteElement(tempList,'e');
	deleteElement(tempList,'a');
	deleteElement(tempList,'o');
	printList(tempList);
	LocateELemList(tempList,'H');
	char e;
	GetElemList(tempList, 4, e);

	insertElement(tempList,'o',1);
	printList(tempList);
}

void basicAddressTest() {
	LNode tempNode1, tempNode2;
	
	tempNode1.data = 4;
	tempNode1.next = NULL;
	
	tempNode2.data = 6;
	tempNode2.next = NULL;
	
	printf("The first node: %d, %d, %d\r\n",&tempNode1, &tempNode1.data, &tempNode1.next);
	printf("The second node: %d, %d, %d\r\n",&tempNode2, &tempNode2.data, &tempNode2.next);
	
	tempNode1.next = &tempNode2;
}

int main() {
	appendInsertDeleteTest();
}

运行结果:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值