一. 算法

通俗的定义:
解题的方法和步骤
狭义的定义:
对存储数据的操作

对不同的存储结构,要完成某一个功能所执行的操作时不一样的
比如:
要输出数组中所有的元素的操作和
要输出链表中所有元素的操作肯定是不一样的
这说明:
算法是依附于存储结构的,不同的存储结构,所执行的算法是不一样的
广义的定义(站在更高的的层次去看):
广义的算法也叫泛型
无论数据是如何存储的,对该数据的操作都是一样的
使用分层思想
我们至少可以通过两个结构来存储数据
  • 数组
    缺点:数组的连续性
分配很大的空间时,没有大块连续区域
插入和删除要动大量的数据(效率低)

优点:存取速度快

  • 链表
    优点:
插入和删除元素效率高
不需要一个连续的很大的内存

缺点:

查找某个位置的元素效率低
链表一个节点中应包含一个指针变量,用它来存放下一个节点的地址

二. 链表

定义:链表是一种常见的重要的数据结构,它是动态的进行存储单元分配的一种结构

说明:

1. 链表的最后一个节点的指针域置成'\0'(NULL)值,标志着链表的结束
2. 每一个链表都用一个“头指针”变量来指向链表的开始,称为head指针,在head指针中存放了链表第一个节点的地址

专业术语:

  • 首节点
存放第一个有效数据的节点
  • 尾结点
存放最后一个有效数据的节点
  • 头节点
头结点的数据类型和首节点的类型是一模一样的
头结点是首节点前面的那个节点
头结点并不存放有效数据
设置头结点的目的是为了方便对链表的操作
  • 头指针
存放头结点地址的指针变量

确定一个链表需要一个参数:头指针

图示理解:

C语言程序设计——链表_链表


举例理解:

#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;
}

图示理解:

  1. 创建链表图示
  2. 遍历链表图示