实验一 单链表实验
1.实验目的
熟悉单链表的定义,单链表的建立方法及相关基本操作,理解单链表的基本思想,能够根据实际情况选择合适的存储结构。
2.实验内容
1、利用头插法或尾插法建立单链表
2、对已建立的单链表实现插入、删除等基本操作;
3、输出链表所有结点数据
4、编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表并计算表长。
3.正文部分
①什么是链表?
本来结构体之间是没有关系的,结构体指针指向毫不相干的三个数据,但是我们让后一个结构体的首地址与前一个结构体的尾部连接起来,形成的链状结构就是链表。简单来说,链表是结构体变量与结构变量通过指针连接在一起的数据结构。
对应下来就是这样(以静态链表为例):
struct Node {
int data; //数据域
struct Node* next //指针域
};
int main()
{
//创建结构体
struct Node Node1 = { 1,NULL }; //数据为1,传递指针为空
struct Node Node2 = { 2,NULL };
struct Node Node3 = { 3,NULL };
//将结构体连接起来(静态链表)
Node1.next = &Node2; //Node1的首地址连接到Node2上
Node2.next = &Node3;
return 0;
}
②如何动态创建一个动态链表?
动态内存申请+模块化设计
- 1.创建链表(创建一个表头表示整个链表)
- 2.创建结点
- 3.插入结点
- 4.删除结点
- 5.打印遍历链表(测试)
③malloc()函数
malloc函数用来动态地分配内存空间,其原型为void* malloc(size_t size);
它在堆区分配一块指定大小的内存空间以用来存放数据。这一块内存空间在函数执行完成后不会被初始化,他们的值是未知的。若分配成功会返回指向该内存的地址,失败则返回NULL。
函数的返回值类型是void*,所以在使用此函数的时候通常需要进行强制类型转换,将void指针转换成我们希望的类型。
#include<stdio.h>
#include<stdlib.h>
struct Node {
int data; //数据域
struct Node* next //指针域
};
struct Node* createList()//创建链表
{
//用指针创建链表表头 让headNode成为结构体变量
struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
//变量使用前必须被初始化
headNode->data = 1;
headNode->next = 1;
}
struct Node* createNode(int data)//创建结点
{
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
}
int main()
{
struct Node* list = createList();//创建链表
system("pause");
return 0;
}
④建立单链表
头插法:按结点的逆序方法逐渐将结点插入到链表的头部。
//头插法插入结点,
void insertNodeByHead(struct Node* headNode, int data)
{
//创建插入的结点
struct Node* newNode = createNode(data);
newNode->next = headNode->next;//新的结点指向原来表头的下一个
headNode->next = newNode;//原来表头的下一个指向新的结点
}
尾插法:按结点的顺序逐渐将结点插入到链表的尾部。
//尾插法插入结点
void insertNodeByTail(struct Node* headNode, int data)
{
struct Node* newNode = createNode(data);
struct Node* posNode = headNode;
while (posNode->next != NULL)
{
posNode = posNode->next;
}
posNode->next = newNode;
}
⑤打印链表
打印链表从表头后的第一个节点开始打印,创建一个pMove指针,每打印完一个结点往下移动一个。
void printList(struct Node* headNode)
{
struct Node* pMove = headNode->next;
while (pMove)
{
printf("%d", pMove->data);
pMove = pMove->next;
}
printf("\n");
}
⑥链表的删除(指定位置删除)
将问题进行转换,指定结点的删除问题可以转换为指定结点的前一个结点跳过指定节点指向指定结点的下一个结点。
free()函数:用来释放动态分配的内存空间,其原型为
void free(void*ptr);
删除结点的函数如下:
void deleteNodeByAppoin(struct Node* headNode, int posData)//删除指定结点
{
struct Node* posNode = headNode->next;//指定位置从表头的下一个找
struct Node* posNodeFront = headNode;//从表头开始找(因为要在指定位置的前一个)
if (posNode == NULL)
printf("无法删除空链表\n");
while (posNode->data != posData)//当指针指向的数据不等于目标数据时
{
posNodeFront = posNode;//指针继续往后查找目标数据
posNode = posNodeFront->next;
if (posNode == NULL)//找到了表尾都没找到
{
printf("没找到相关信息,无法删除\n");
return;
}
}
posNodeFront->next = posNode->next;//前面结点的next指向后面结点的next
free(posNode);
}
⑦完整代码
完整源码下载:数据结构——单链表实验