数据结构---单链表

单链表是一种先行表链接存储表示。链表是由N个节点组成的,每个节点可以包括两个部分:1、数据结构体  2、指向下一个节点的指针

typedef int DataType;
//node结构体
typedef struct node
{
	DataType data;
	struct node *Link;

}ListNode;

链表相对于数组的优势是,可以在内存中随机找个空间,可以是连续的,也可以是不连续,但是要保证空间能容的下一个节点的大小。


最要在链表的第一个给一个空头,好处是把这个空头的位置定义为0,有数据的第一个定义为1,这样方便查找。

还有图个好处插入的时候可以不用管是不是头节点直接用一种方式插入就好,要是没有头节点的话,就要考虑是不是头节点的问题了。

给出两个重要的操作  增加和删除

1、增加(加入要插入到第n个位置)

增加头节点的时候只要记住:四步:

a、malloc一个节点

b、找到n-1位置上的节点

c、把第n个节点和新节点连接起来

d、把第n个和第n-1个节点断开,同时把n-1个节点个新节点连上

int Insert(ListNode *first, int i, DataType x)
{
	//备份指针
	ListNode *temp = first;
	//为新的节点分配空间
	ListNode *newnode = (ListNode *)malloc(sizeof(ListNode));
	//判断空间是否分配成功
	if (!newnode)
	{
		printf("分配失败\n");
		return 0;
	}
	//给新节点赋值
	newnode->data = x;
	newnode->Link = NULL;
	//寻找要插入位置的前一个节点
	for (int count = 0; count < i-1 ; count++)
	{
		temp = temp->Link;
	}
	//先把要插入节点位置原来的节点连接到新节点上,然后再把要插入节点的前一个节点和新节点连接起来
	newnode->Link = temp->Link;
	temp->Link = newnode;
	return 1;

}

2、删除(加入要删除出第N个)

这分三步走:

a、找到第n-1个节点

b、把n-1和n+1节点连上

c、free掉节点n

void reMove(ListNode *first, int i, DataType x)
{
	//备份指针
	ListNode *temp = first,*pBefore,*pCurr;
	//判断位置是否正确
	if (i > getLength(first))
	{
		printf("位置错误\n");
		return;
	}
	//寻找要删除位置的前一个节点
	for (int count = 0; count < i - 1; count++)
	{
		temp = temp->Link;
	}
	//确定删除节点之前的节点
	pBefore = temp;
	//确认删除的节点
	pCurr = temp->Link;
	if (pCurr->data != x)
	{
		printf("请输入正确的数据\n");
		return;
	}
	//把要删除节点的前一个和后一个连接上
	pBefore->Link = pCurr->Link;
	//释放要删除的节点
	free(pCurr);

}

有几个需要注意的地方:

1)定义指针时而且要使用指针指向某个结构体或者字符串的时候,需要分配内存空间大小(这个很重要,经常有人会忘记,导致段错误或者内存错误访问的错误)

2)当指针位及时被使用时需要把指针指向NULL

这个还有一个要注意:NULL就是NULL不是0地址,也不是其他的什么地址,不要勿以为是0(判断指针时候要用 p==NULL或者p !=NULL,我上面有的写的不够规范,大家见谅)


下面给出全部代码

头文件:

#ifndef _HEAD_H_
#define _HEAD_H_
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0

typedef int DataType;
//node结构体
typedef struct node
{
	DataType data;
	struct node *Link;

}ListNode;

//初始化函数
void initList(ListNode *first);
//计算链表长度
int getLength(ListNode *first);
//插入函数
int Insert(ListNode *first, int i, DataType x);
//输出内容
void outPut(ListNode *first);
//删除节点
void reMove(ListNode *first, int i, DataType x);
//查找结点
int Search(ListNode *first, DataType x);

void printMsg();

int getOption();
#endif

函数文件

#include "head.h"

void initList(ListNode *first)
{	
	//如果失败就返回
	if (!first)
	{
		printf("分配空间失败\n");
		return;
	}
	//把下一个节点置空,因为原则上不允许野指针,这很危险
	first->Link = NULL;
}

int getLength(ListNode *first)
{
	//备份指针,为了不影响后面的操作
	ListNode *temp = first->Link;
	int count = 0;
	while (temp != NULL)
	{
		temp = temp->Link;
		count++;
	}
	return count;
}
int Insert(ListNode *first, int i, DataType x)
{
	//备份指针
	ListNode *temp = first;
	//为新的节点分配空间
	ListNode *newnode = (ListNode *)malloc(sizeof(ListNode));
	//判断空间是否分配成功
	if (!newnode)
	{
		printf("分配失败\n");
		return 0;
	}
	//给新节点赋值
	newnode->data = x;
	newnode->Link = NULL;
	//寻找要插入位置的前一个节点
	for (int count = 0; count < i-1 ; count++)
	{
		temp = temp->Link;
	}
	//先把要插入节点位置原来的节点连接到新节点上,然后再把要插入节点的前一个节点和新节点连接起来
	newnode->Link = temp->Link;
	temp->Link = newnode;
	return 1;

}

void outPut(ListNode *first)
{
	//备份指针
	ListNode *temp = first;
	//判断链表是否为空
	if (!temp->Link)
	{
		printf("链表是空的\n");
		return;
	}
	//循环输出内容
	for (int i = 0; i < getLength(first); i++)
	{
		temp = temp->Link;
		printf("%d  ", temp->data);
	}
	printf("\n");
}

void reMove(ListNode *first, int i, DataType x)
{
	//备份指针
	ListNode *temp = first,*pBefore,*pCurr;
	//判断位置是否正确
	if (i > getLength(first))
	{
		printf("位置错误\n");
		return;
	}
	//寻找要删除位置的前一个节点
	for (int count = 0; count < i - 1; count++)
	{
		temp = temp->Link;
	}
	//确定删除节点之前的节点
	pBefore = temp;
	//确认删除的节点
	pCurr = temp->Link;
	if (pCurr->data != x)
	{
		printf("请输入正确的数据\n");
		return;
	}
	//把要删除节点的前一个和后一个连接上
	pBefore->Link = pCurr->Link;
	//释放要删除的节点
	free(pCurr);

}

int isEmpty(ListNode *first)
{
	return (first->Link == NULL) ? 1 : 0;
}

int Search(ListNode *first, DataType x)
{
	ListNode *temp = first;
	int i = 0;
	//判断链表是否为空
	if (!temp->Link)
	{
		printf("链表是空的\n");
		return -1;
	}
	while (temp->data != x)
	{
		i++;
		temp = temp->Link;
	}
	return i;
}

void printMsg()
{
	printf("1、插入一个数据\n");
	printf("2、删除一个数据\n");
	printf("3、获得一个元素位子\n");
	printf("4、查看所有数据\n");
	printf("5、查看表是否为空\n");
	printf("6、退出\n");
	printf(">> ");
}

int getOption()
{//获取用户输入操作  
	char input;
	scanf("%c", &input);
	_flushall();
	//fflush(stdin);	
	//input=toupper(input);  
	return input;
}

main函数

#include "head.h"

void main(void)
{
	int i,x,op;
	ListNode first;
	initList(&first);
	printMsg();
	while (op = getOption())
	{
		switch (op)
		{
		case '1':
			printf("请输入位置和元素\n");
			scanf("%d %d", &i, &x);
			_flushall();
			Insert(&first,i,x);
			printf("插入元素%d", x);
			break;
		case '2':
			printf("请输入位置和元素\n");
			scanf("%d %d", &i, &x);
			_flushall();
			reMove(&first, i, x);
			printf("删除元素%d\n", x);
			break;
		case '3':
			printf("请输入要查找的元素\n");
			scanf("%d", &x);
			_flushall();
			printf("元素在%d\n", Search(&first,x));
			break;
		case '4':
			outPut(&first);
			break;
		case '5':
			printf("%d", isEmpty(&first));
			break;

		case '6':
			printf("---byebye----");
			return;
			break;
		default:
			break;
		}
		printf("\n>> ");
	}
	system("pause");
}

程序的封装和接口的概念很重要,要尽量使用接口的封装

                                                              

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单链表是一种常见的数据结构,它由一个或多个节点组成,每个节点包含一个数据域和一个指针域,指针域指向下一个节点。 实现单链表的查找位序算法函数需要以下步骤: 1. 定义一个指针p指向链表的头节点,并定义一个变量count,用于计数。 2. 从头节点开始,遍历链表,当p指向某个节点时,计数器count加1。 3. 如果p指向的节点的数据与目标数据相等,则返回当前的计数器count,即为目标数据的位序。 4. 如果p指向的节点不是目标数据,则将p指向下一个节点,重复步骤3。 5. 如果遍历完链表后仍未找到目标数据,则返回-1,表示未找到。 下面是C语言实现单链表查找位序算法函数的代码示例: ```c #include <stdio.h> #include <stdlib.h> // 定义单链表节点结构 typedef struct Node { int data; // 数据域 struct Node* next; // 指针域 } Node; // 查找位序的算法函数 int findPosition(Node* head, int target) { Node* p = head; // 指向头节点 int count = 0; // 计数器初始化为0 while (p != NULL) { count++; // 计数器加1 if (p->data == target) { return count; // 找到目标数据,返回当前计数器的值 } p = p->next; // 指向下一个节点 } return -1; // 遍历完链表未找到目标数据,返回-1 } int main() { // 创建链表 Node* head = (Node*)malloc(sizeof(Node)); head->data = 1; // 头节点数据为1 Node* node1 = (Node*)malloc(sizeof(Node)); node1->data = 2; Node* node2 = (Node*)malloc(sizeof(Node)); node2->data = 3; head->next = node1; node1->next = node2; node2->next = NULL; // 查找位序示例 int target = 3; // 目标数据为3 int position = findPosition(head, target); if (position != -1) { printf("目标数据 %d 的位序为 %d\n", target, position); } else { printf("未找到目标数据 %d\n", target); } // 释放链表内存 free(node2); free(node1); free(head); return 0; } ``` 在上述代码中,我们首先定义了一个指向头节点的指针p和一个计数器count,然后使用while循环遍历链表。当p指向某个节点时,计数器加1,并判断该节点的数据是否与目标数据相等。如果找到了目标数据,则返回当前计数器的值,即为目标数据的位序。如果遍历完链表仍未找到目标数据,则返回-1表示未找到。最后在主函数中演示了调用该算法函数的示例。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值