一. 算法
通俗的定义:
解题的方法和步骤
狭义的定义:
对存储数据的操作
对不同的存储结构,要完成某一个功能所执行的操作时不一样的
比如:
要输出数组中所有的元素的操作和
要输出链表中所有元素的操作肯定是不一样的
这说明:
算法是依附于存储结构的,不同的存储结构,所执行的算法是不一样的
广义的定义(站在更高的的层次去看):
广义的算法也叫泛型
无论数据是如何存储的,对该数据的操作都是一样的
使用分层思想
我们至少可以通过两个结构来存储数据
- 数组
缺点:数组的连续性
分配很大的空间时,没有大块连续区域
插入和删除要动大量的数据(效率低)
优点:存取速度快
- 链表
优点:
插入和删除元素效率高
不需要一个连续的很大的内存
缺点:
查找某个位置的元素效率低
链表一个节点中应包含一个指针变量,用它来存放下一个节点的地址
二. 链表
定义:链表是一种常见的重要的数据结构,它是动态的进行存储单元分配的一种结构
说明:
1. 链表的最后一个节点的指针域置成'\0'(NULL)值,标志着链表的结束
2. 每一个链表都用一个“头指针”变量来指向链表的开始,称为head指针,在head指针中存放了链表第一个节点的地址
专业术语:
- 首节点
存放第一个有效数据的节点
- 尾结点
存放最后一个有效数据的节点
- 头节点
头结点的数据类型和首节点的类型是一模一样的
头结点是首节点前面的那个节点
头结点并不存放有效数据
设置头结点的目的是为了方便对链表的操作
- 头指针
存放头结点地址的指针变量
确定一个链表需要一个参数:头指针
图示理解:
举例理解:
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
//定义了一个链表节点的数据类型
struct Node
{
int data; //数据域
struct Node *pNext; //指针域,pNext存放了 struct Node类型变量的地址,所以它本身也是这个类型
};
//函数声明
struct Node * CreateList(void);
void TraverseList(struct Node *pHead);
int main(void)
{
struct Node *pHead = NULL; //pHead用来存放链表头结点的地址
pHead = CreateList(); //只需知道链表头结点的地址,就能找到链表,并获取里面的每一个元素 ,动态创建一个链表
TraverseList(pHead); //遍历输出
return 0;
}
struct Node * CreateList(void) //函数返回值是: struct Node *类型
{
int len; //用来存放有效节点的个数
int i;
int val; //用来临时存放用户输入的节点的值
//分配一个不存放有效数据的头结点
struct Node *pHead = (struct Node *)malloc(sizeof(struct Node));
if(NULL == pHead)
{
printf("分配失败,程序终止!");
exit(-1);
}
struct Node *pTail = pHead;
pTail->pNext = NULL; //等价于(*pTail).pNext
printf("请输入您要生成的链表节点的个数:len = ");
scanf("%d", &len);
for(i=0; i<len; ++i)
{
printf("请输入第%d个节点的值:", i+1);
scanf("%d", &val);
struct Node *pNew = (struct Node *)malloc(sizeof(struct Node));
if(NULL == pNew)
{
printf("分配失败,程序终止!\n");
exit(-1);
}
pNew->data = val; //等价于(*pNew).data
pTail->pNext = pNew; //表示(*pTail).pNext指向了以pNew内容为地址的变量
pNew->pNext = NULL;
pTail = pNew;
}
return pHead;
}
bool empty_list(struct Node *pHead)
{
if(pHead->pNext == NULL) //pHead->pNext == (*pHead).pNext
return true;
else
return false;
}
void TraverseList(struct Node *pHead)
{
/*
if( empty_list(pHead) )
{
printf("链表为空");
}
*/
struct Node *p = pHead->pNext; //表示(*pHead).pNext指针变量的内容发送给了指针变量p
while(NULL != p)
{
printf("%d\n", p->data);
p = p->pNext; //等价于把(*p).pNext里面存放的地址复制一份替换了原来p里面存放的地址
}
return;
}
图示理解:
- 创建链表图示
- 遍历链表图示