带头结点的单链表的几个应用(C语言实现)

目录

查找单链表倒数第index个结点并显示出来

单链表逆序(反转)

单链表逆序打印(原始单链表不变)

合并两个有序的单链表


查找单链表倒数第index个结点并显示出来

思路分析:

编写一个函数接收head结点、index (index就是倒数第index个结点)
1.先遍历的到链表总长度 size 
2.得到size后,再遍历一遍找到第(size - index)个结点,就是我们要找的倒数第index个结点
3.没有找到就直接返回NULL

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

//单链表的结点定义 
typedef struct Node{
	int no;   //编号 
	char name[10];  //姓名
	struct Node *next;  //Node类型的next指针 
}SLNode;

//单链表结点的初始化
void ListInitiate(SLNode **head){
	*head = (SLNode *)malloc(sizeof(SLNode));  //申请头节点,由head指示其地址
	(*head)->next = NULL;  //置结束标记NULL 
} 

//求当前数据元素个数
int ListLength(SLNode *head){
	SLNode *temp = head;  //头结点不能动,temp指向head
	int count = 0;   //count初始化为0 
	
	while(temp->next != NULL){  //循环计数,temp->next == NULL时,指向单链表的最后一个元素 
		temp = temp->next;  //指向下一个结点 
		count++;  //计数器加1 
	}
	return count;
}

//直接插入链表尾部
void AddList(SLNode *head, SLNode *node){
	SLNode *temp = head;  //头结点不能动,所以需要辅助遍历指针temp 
	
	while(temp->next != NULL)  //遍历找到temp最后一个结点位置 
		temp = temp->next;  //没有到最后就指向下一个结点位置
		
	//当推出while循环时,temp指向了最后一个结点
	//让temp的next指向待插入的结点
	temp->next = node; 
} 

//显示链表【遍历】
int ShowList(SLNode *head){
	//定义temp辅助遍历 
	SLNode *temp = head->next;
	
	//判断链表是否为空 
	if(head->next == NULL){
		printf("链表为空\n");
		return 0;
	}
	
	//遍历单链表 
	while(temp != NULL){
		printf("[%d,%s]\n",temp->no,temp->name);  //打印链表结点 
		temp = temp->next;  //指向下一个结点 
	}
	
	return 1;
} 

//查找倒数第k个元素
//编写一个函数接收head结点、index 
//index就是倒数第index个结点
//1.先遍历的到链表总长度 size 
//2.得到size后,再遍历一遍找到第(size - index)个结点,就是我们要找的倒数第index个结点
//3.没有找到就直接返回NULL 
SLNode *FindReciprocal(SLNode *head, int index){
	SLNode *temp = head->next;  //头结点不能动,temp指向head->next
	int size, i;  //接收链表长度
	
	//判断链表是否为空,如果为空,则直接返回NULL
	if(head->next == NULL){
		printf("链表为空,没有倒数 %d 个元素\n", index);
		return NULL;
	} 
	
	//遍历得到链表长度 
	size = ListLength(head);
	
	//判断链表长度是否正常,是否含有倒数第index个结点
	if(size <= 0 || index > size){
		printf("链表长度为 %d , 没有倒数第 %d 个元素\n", size, index);
		return NULL;
	} 
	
	//如果没有上述情况,则for循环找到 倒数第index个结点
	for(i = 0; i < size - index; i++){
		temp = temp->next;
	}
	
	return temp;
} 

//撤销单链表
void Destroy(SLNode **head){
	//定义辅助指针 ,head暂时不能没有,故temp1指向head,temp2配合释放掉 
	SLNode *temp1 = NULL, *temp2 = NULL;
	
	//定义temp1辅助遍历 
	temp1 = *head;
	while(temp1 != NULL){  //最终:temp1 = NULL,temp2被释放 
		temp2 = temp1;   //temp2指向temp1,便于释放 
		temp1 = temp1->next;  //temp1指向下一个,避免链表丢失 
		free(temp2);  //释放temp2 
		temp2 = NULL;  //避免free都成为“野指针” 
	}
	*head = NULL;  //最后让head = NULL 
} 

//测试一下 
int main(int argc, char *argv[]) {
	SLNode *head;
	SLNode *node1, *node2, *node3, *node;   //定义测试结点
	int index;
	
	//初始化各结点
	ListInitiate(&head);
	ListInitiate(&node1);
	ListInitiate(&node2);
	ListInitiate(&node3);
	ListInitiate(&node);
	
	//定义各结点 
	node1->no = 1;
	strcpy(node1->name, "Lucy");
	node2->no = 2;
	strcpy(node2->name, "Jimy");
	node3->no = 3;
	strcpy(node3->name, "Zoma");
	
	//插入链表尾部
	AddList(head, node1);
	AddList(head, node3);
	AddList(head, node2);
	
	//显示链表
	printf("修改前链表信息如下:\n");
	ShowList(head);
	
	printf("当前链表长度为 %d , 请输入你需要查找的倒数第index个结点\n", ListLength(head));
	scanf("%d", &index);
	
	//测试 
	node = FindReciprocal(head, index);
	if(node != NULL)
		printf("倒数第 %d 个结点的信息为:[%d, %s]\n", index, node->no, node->name); 
	
	//撤销单链表	
	Destroy(&head);
	
	return 0;
}

 单链表逆序(反转)

思路分析:

定义一个新的头结点,每遍历原始单链表的一个结点,就将其取出,放在新的头结点的前端以实现反转 

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

//单链表的结点定义 
typedef struct Node{
	int no;   //编号 
	char name[10];  //姓名
	struct Node *next;  //Node类型的next指针 
}SLNode;

//单链表结点的初始化
void ListInitiate(SLNode **head){
	*head = (SLNode *)malloc(sizeof(SLNode));  //申请头节点,由head指示其地址
	(*head)->next = NULL;  //置结束标记NULL 
} 

//直接插入链表尾部
void AddList(SLNode *head, SLNode *node){
	SLNode *temp = head;  //头结点不能动,所以需要辅助遍历指针temp 
	
	while(temp->next != NULL)  //遍历找到temp最后一个结点位置 
		temp = temp->next;  //没有到最后就指向下一个结点位置
		
	//当推出while循环时,temp指向了最后一个结点
	//让temp的next指向待插入的结点
	temp->next = node; 
} 

//显示链表【遍历】
int ShowList(SLNode *head){
	//定义temp辅助遍历 
	SLNode *temp = head->next;
	
	//判断链表是否为空 
	if(head->next == NULL){
		printf("链表为空\n");
		return 0;
	}
	
	//遍历单链表 
	while(temp != NULL){
		printf("[%d,%s]\n",temp->no,temp->name);  //打印链表结点 
		temp = temp->next;  //指向下一个结点 
	}
	
	return 1;
} 

//单链表反转
//定义一个新的头结点,每遍历原始单链表的一个结点,就将其取出,放在新的头结点的前端以实现反转 
int ReverseList(SLNode *head){
	//定义辅助指针帮助我们遍历, cur:当前结点,next:cur的下一个结点 
	SLNode *cur = head->next, *next = NULL;
	SLNode *newhead;  //定义一个新的头结点
	
	//初始化新的头结点 
	ListInitiate(&newhead);
	
	//如果单链表为空或只有一个结点则直接返回 
	if(head->next == NULL || head->next->next == NULL)
		return 0;
	
	while(cur != NULL){
		next = cur->next;  //暂时保存当前节点的下一个结点,因为后面需要
		cur->next = newhead->next;  //插入结点步骤一:当前结点的next指向新的链表的头结点的下一个结点
		newhead->next = cur;  //插入步骤二:新的头指针的next指向当前结点
		cur = next;  //cur后移,指向原单链表的下一个结点 
	} 
	
	//最后将原单链表的head->next指向newhead->next,以实现单链表的反转
	head->next = newhead->next;
	
	free(newhead);  //释放newhead 
	newhead->next = NULL;  //避免成为“野指针” 
	
	return 1; 
} 

//撤销单链表
void Destroy(SLNode **head){
	//定义辅助指针 ,head暂时不能没有,故temp1指向head,temp2配合释放掉 
	SLNode *temp1 = NULL, *temp2 = NULL;
	
	//定义temp1辅助遍历 
	temp1 = *head;
	while(temp1 != NULL){  //最终:temp1 = NULL,temp2被释放 
		temp2 = temp1;   //temp2指向temp1,便于释放 
		temp1 = temp1->next;  //temp1指向下一个,避免链表丢失 
		free(temp2);  //释放temp2 
		temp2 = NULL;  //避免free都成为“野指针” 
	}
	*head = NULL;  //最后让head = NULL 
} 


//测试 
int main(int argc, char *argv[]) {
	SLNode *head;
	SLNode *node1, *node2, *node3, *node4;   //定义测试结点
	
	//初始化各结点
	ListInitiate(&head);
	ListInitiate(&node1);
	ListInitiate(&node2);
	ListInitiate(&node3);
	ListInitiate(&node4);
	
	//定义各结点 
	node1->no = 1;
	strcpy(node1->name, "Lucy");
	node2->no = 2;
	strcpy(node2->name, "Jimy");
	node3->no = 3;
	strcpy(node3->name, "Zoma");
	node4->no = 4;
	strcpy(node4->name, "Linda");
	
	//插入链表尾部
	AddList(head, node1);
	AddList(head, node3);
	AddList(head, node2);
	AddList(head, node4);
	
	//显示链表
	printf("反转前链表信息如下:\n");
	ShowList(head);
	
	//测试 
	ReverseList(head);
	printf("反转后链表信息如下:\n");
	ShowList(head); 
	
	//撤销单链表
	Destroy(&head);
	return 0;
}

 单链表逆序打印(原始单链表不变)

思路分析:

可以利用栈这个数据结构,将各个结点压入栈中,再利用栈先进后出的特点,将单链表逆序打印

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

//单链表、链式栈的结点定义 
typedef struct Node{
	int no;   //编号 
	char name[10];  //姓名
	struct Node *next;  //Node类型的next指针 
}LNode;

//单链表、链式栈结点的初始化
void ListInitiate(LNode **head){
	*head = (LNode *)malloc(sizeof(LNode));  //申请头节点,由head指示其地址
	(*head)->next = NULL;  //置结束标记NULL 
} 

//直接插入链表尾部
void AddList(LNode *head, LNode *node){
	LNode *temp = head;  //头结点不能动,所以需要辅助遍历指针temp 
	
	while(temp->next != NULL)  //遍历找到temp最后一个结点位置 
		temp = temp->next;  //没有到最后就指向下一个结点位置
		
	//当推出while循环时,temp指向了最后一个结点
	//让temp的next指向待插入的结点
	temp->next = node; 
} 

//链式栈非空否
int StackNotEmpty(LNode *shead){
	if(shead->next == NULL)
		return 0;  //栈空返回0
	else
		return 1;  //栈非空返回1 
} 

//入栈 
void StackPush(LNode *shead, LNode *node){
	//把单链表结点插入链式栈shead的 栈顶作为新的栈顶 
	node->next = shead->next;  //插入步骤一:新的结点的next指向shead的next 
	shead->next = node;   //插入步骤二:shead的next指向新的结点 
}

//出栈(不带回栈顶元素,只是打印出来)
LNode *StackPop(LNode *shead) {
	//出栈成功返回1,出栈失败返回0
	LNode *temp = shead->next;  //设置temp指向栈顶结点
	LNode *snode = NULL;  //将原栈顶元素返回 
	
	ListInitiate(&snode);  //初始化 原栈顶结点
	
	//判断栈是否空
	if(!StackNotEmpty(shead)){
		printf("链式栈已空出错!\n");
		return NULL;
	} 
	
	snode = temp;  //将 原栈顶结点 返回 
	shead->next = temp->next;  //删除原栈顶结点
	free(temp);  //释放原栈顶结点内存空间 
	temp->next = NULL;  //避免“野指针”
	
	return snode; 
}

//显示链表【遍历】
int ShowList(LNode *head){
	//定义temp辅助遍历 
	LNode *temp = head->next;
	
	//判断链表是否为空 
	if(head->next == NULL){
		printf("链表为空\n");
		return 0;
	}
	
	//遍历单链表 
	while(temp != NULL){
		printf("[%d,%s]\n",temp->no,temp->name);  //打印链表结点 
		temp = temp->next;  //指向下一个结点 
	}
	
	return 1;
} 

//撤销单链表、链式栈 
void Destroy(LNode **head){
	//定义辅助指针 ,head暂时不能没有,故temp1指向head,temp2配合释放掉 
	LNode *temp1 = NULL, *temp2 = NULL;
	
	//定义temp1辅助遍历 
	temp1 = *head;
	while(temp1 != NULL){  //最终:temp1 = NULL,temp2被释放 
		temp2 = temp1;   //temp2指向temp1,便于释放 
		temp1 = temp1->next;  //temp1指向下一个,避免链表丢失 
		free(temp2);  //释放temp2 
		temp2 = NULL;  //避免free都成为“野指针” 
	}
	*head = NULL;  //最后让head = NULL 
} 

//单链表逆序打印 
//可以利用栈这个数据结构,将各个结点压入栈中,再利用栈先进后出的特点,将单链表逆序打印
int ReversePrint(LNode *head){
	//定义cur助遍历 ,next 指向 cur下一个结点 ,snode复制一份单链表结点信息 
	LNode *cur = head->next, *next = NULL, *snode;
	LNode *shead;  //定义链式栈头结点
	
	//初始化 
	ListInitiate(&shead);
	ListInitiate(&snode); 
	
	//判断单链表是否为空,为空则直接返回
	if(head->next == NULL){
		printf("单链表为空\n");
		return 0;
	} 
	
	//将单链表所有结点压入栈中
	while(cur != NULL){
		next = cur->next;
		StackPush(shead, cur);
		cur = next;
	} 
	
	//重新组成原始单链表 
	head->next = NULL;
	
	//将栈中所有元素打印,pop出栈
	printf("逆序打印结果如下:\n"); 
	while(StackNotEmpty(shead)){
		snode = StackPop(shead);
		printf("[%d, %s]\n", snode->no, snode->name);
		snode->next = head->next;
		head->next = snode;
	}
	
	//撤销链式栈
	Destroy(&shead); 
	return 1;
} 

//测试 
int main(int argc, char *argv[]) {
	LNode *head;  //定义头指针变量
	LNode *node1, *node2, *node3, *node4;   //定义测试结点
	
	//初始化各结点
	ListInitiate(&head);
	ListInitiate(&node1);
	ListInitiate(&node2);
	ListInitiate(&node3);
	ListInitiate(&node4);
	
	//定义各结点 
	node1->no = 1;
	strcpy(node1->name, "Lucy");
	node2->no = 2;
	strcpy(node2->name, "Jimy");
	node3->no = 3;
	strcpy(node3->name, "Zoma");
	node4->no = 4;
	strcpy(node4->name, "Candy");
	
	//插入链表尾部
	AddList(head, node1);
	AddList(head, node3);
	AddList(head, node2);
	AddList(head, node4);
	
	//显示链表
	printf("逆序打印前链表信息如下:\n");
	ShowList(head);
	
	//测试
	ReversePrint(head);
	
	printf("逆序打印后链表信息如下:\n");
	ShowList(head); 
	
	//撤销单链表
	Destroy(&head);
	return 0;
}

 合并两个有序的单链表

思路如下:

定义一个新的头结点,对比两个有序单链表的编号,小的结点指向新的链表的末端

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

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

//单链表的结点定义 
typedef struct Node{
	int no;   //编号 
	char name[10];  //姓名
	struct Node *next;  //Node类型的next指针 
}SLNode;

//单链表结点的初始化
void ListInitiate(SLNode **head){
	*head = (SLNode *)malloc(sizeof(SLNode));  //申请头节点,由head指示其地址
	(*head)->next = NULL;  //置结束标记NULL 
} 

//按照编号顺序插入链表
int AddByOrder(SLNode *head, SLNode *node){
	SLNode *temp = head;  //头结点不能动,所以需要辅助遍历指针temp 
	
	//temp->next == NULL时,直接插入最后即可。
	//temp->next->no > node->no时,说明已经找到。
	//这里要特别注意是 temp->next->no,而不是temp->no,因为 temp->no是头结点的,而头结点没有信息 
	while(temp->next != NULL && temp->next->no < node->no) {
		temp = temp->next;
	}

	//判断temp->no是否等于node->no ,如果等于,则说明该编号结点已存在,不能插入
	//要加上 temp->next != NULL 这个判断条件,否则,在链表为空时,temp->next->no会出现错误 
	if(temp->next != NULL && temp->next->no == node->no){
		printf("编号为 %d 的结点已存在,不能插入\n", node->no);
		return 0;
	}
	
	//否则,则可以插入链表
	node->next = temp->next;  //新的结点->next = temp->next 
	temp->next = node;  //temp->next = 新的结点 
	
	return 1;
} 

//显示链表【遍历】
int ShowList(SLNode *head){
	//定义temp辅助遍历 
	SLNode *temp = head->next;
	
	//判断链表是否为空 
	if(head->next == NULL){
		printf("链表为空\n");
		return 0;
	}
	
	//遍历单链表 
	while(temp != NULL){
		printf("[%d,%s]\n",temp->no,temp->name);  //打印链表结点 
		temp = temp->next;  //指向下一个结点 
	}
	
	return 1;
} 

//撤销单链表
void Destroy(SLNode **head){
	//定义辅助指针 ,head暂时不能没有,故temp1指向head,temp2配合释放掉 
	SLNode *temp1 = NULL, *temp2 = NULL;
	
	//定义temp1辅助遍历 
	temp1 = *head;
	while(temp1 != NULL){  //最终:temp1 = NULL,temp2被释放 
		temp2 = temp1;   //temp2指向temp1,便于释放 
		temp1 = temp1->next;  //temp1指向下一个,避免链表丢失 
		free(temp2);  //释放temp2 
		temp2 = NULL;  //避免free都成为“野指针” 
	}
	*head = NULL;  //最后让head = NULL 
} 

//将两个有序单链表合并成一个有序单链表
SLNode *MergeOrderedList(SLNode *head1, SLNode *head2){
	//定义合并链表的头结点, 设置辅助遍历指针 
	SLNode *head = NULL, *temp = NULL, *temp1 = head1->next, *temp2 = head2->next;
	
	//初始化temp
	ListInitiate(&head);
	ListInitiate(&temp);
	temp = head; 
	
	//讨论两个链表都为空的情况 
	if(temp1 == NULL && temp2 == NULL){
		printf("两个链表为空,不能合并!\n");
		return NULL;
	}
	
	// 两个链表都不为空时 
	while(temp1 != NULL && temp2 != NULL){
		if(temp1->no <= temp2->no){  //当temp1的 no 编号小于或等于 temp2的 no 编号时 
			temp->next = temp1;  //temp指向temp1所指向的结点 
			temp = temp->next;  //temp 后移 
			temp1 = temp1->next;   //temp1 后移 
			
		}else{  //当temp1的 no 编号大于于 temp2的 no 编号时 
			temp->next = temp2;  //temp指向temp2所指向的结点
			temp = temp->next;  //temp 后移
			temp2 = temp2->next;   //temp2 后移 
			
		}
	}
	
	//讨论其一链表为空的情况 
	if(temp1 != NULL){
		temp->next = temp1;  //如果单链表一没有被遍历完,则直接让temp指向temp1 
	}
	if(temp2 != NULL){
		temp->next = temp2;  //如果单链表一没有被遍历完,则直接让temp指向temp2
	}
	
	//撤销单链表一、单链表二 
	head1->next = NULL;
	head2->next = NULL;
	return head; 
}

int main(int argc, char *argv[]) {
	SLNode *head, *head1, *head2;  //定义头指针变量
	SLNode *node1, *node2, *node3, *node4, *node5, *node6;   //定义测试结点
	
	//初始化各结点
	ListInitiate(&head);
	ListInitiate(&head1);
	ListInitiate(&head2);
	ListInitiate(&node1);
	ListInitiate(&node2);
	ListInitiate(&node3);
	ListInitiate(&node4);
	ListInitiate(&node5);
	ListInitiate(&node6);
	
	//定义各结点 
	node1->no = 1;
	strcpy(node1->name, "Lucy");
	node2->no = 3;
	strcpy(node2->name, "Jimy");
	node3->no = 5;
	strcpy(node3->name, "Zoma");
	node4->no = 2;
	strcpy(node4->name, "Candy");
	node5->no = 4;
	strcpy(node5->name, "Linda");
	node6->no = 5;
	strcpy(node6->name, "Joy");
	
	//按照编号插入
	AddByOrder(head1, node2);
	AddByOrder(head1, node1);
	AddByOrder(head1, node3); 
	AddByOrder(head2, node5);
	AddByOrder(head2, node4);
	AddByOrder(head2, node6); 
	
	//显示链表
	printf("有序单链表1信息如下:\n");
	ShowList(head1);
	printf("有序单链表2信息如下:\n");
	ShowList(head2);
	
	//测试合并两个有序单链表
	head = MergeOrderedList(head1, head2); 
	
	//显示合并后的单链表,查看是否正确 
	if(head != NULL){
		printf("合并后的有序单链表如下:\n");
		ShowList(head);
	}
		
	//撤销单链表
	Destroy(&head);
	return 0;
}

 本篇参考:

尚硅谷Java数据结构与java算法(Java数据结构与算法)

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/*带头点头文件 hlinklist.h*/ #include <stdio.h> typedef int datatype; typedef struct link_node { datatype data; struct link_node *next; }node; /*初始化链表*/ node *init() { node *head; head=(node *)malloc(sizeof(node)); head->next=0; return head; } /*尾插法创建一个带头链表*/ node *creat(node *head) { node *r,*s; int x; r=head; printf("在新链表中输入数据以0束:"); scanf("%d",&x); while(x) { s=(node*)malloc(sizeof(node)); s->data=x; r->next=s; r=s; scanf("%d",&x); } r->next=0; return head; } /*打印链表点值*/ void print(node *head) { node *p; p=head->next; if(!p) printf("链表内容为空!"); else while(p) { printf("%5d",p->data); p=p->next; } printf("\n"); } /*在链表中查找第i个点的地址*/ node *find(node *head,int i) { node *p=head; int j=0; if(i<0) {printf("不存在!");return 0;} if(i==0) return head; while(p&&i!=j) { p=p->next; j++; } return p; } /*在带头点的链表第i个位置后插入一个数*/ node *insert(node *head,int i,datatype x) { node *p,*q; q=find(head,i); if(!q) { printf("插入的位置不存在!\n");return head;} else { p=(node *)malloc(sizeof(node)); p->data=x; p->next=q->next; q->next=p; } return head; } /*在带头点的链表中删除一个为x的值*/ node *dele(node *head,datatype x) { node *pre=head,*p; p=head; while(p&&p->data!=x) { pre=p;p=p->next; } if(p) { pre->next=p->next; free(p); } return head; } /*把带头点的链表倒置(以点形式 )*/ node *Dao_zhi(node *head) { node *p,*s; p=head->next; head->next=NULL; while(p) { s=p; p=p->next; s->next=head->next; head->next=s; } return head; } /*删除链表中重复的点 */ node *dele1(node *head) { node *pre,*p,*q; if(head->next==0||!head->next->next) { printf("链表为空!"); return head; } //pre=head->next; q=head->next; while(q) { pre=q; p=q->next; while(p) { while(p&&q->data!=p->data) { pre=p;p=p->next; } if(p) { pre->next=p->next; free(p); } p=pre->next; } q=q->next; } return head; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值