目录
查找单链表倒数第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;
}
本篇参考: