前置知识:
内存区域:
一.内存四区:
- 代码区:函数代码 存放在代码区 函数名就是函数地址。
- 全局区:全局的变量 字符串常量 初始化 int a = 0;
- 栈 区:告诉计算机 int double char 定义一个变量c,系统开辟 释放。
- 堆 区:自己确定有多大,装什么数据?用完之后是否继续用?自己决定开辟,释放。
例如:其中的b,c,d就是定义在栈区。
int main(){
int b;
float c;
double d;
}
4个字节可以用以下存放:
1.char c[4];
2.int
3.float
4.short c[2];
#include<stdlib.h>
int *p;
p = (int *)malloc(size); //在堆区开辟size个字节的内存,指针p指向这段内存
//(用malloc开辟的内存,不会自己释放,需要主动释放)
free(p); //释放
任何数据都可以用malloc()。
二、数据结构:
用一套具体的方法,管理这些内存。高效有序
- 链表:内存之间互相连接的一种数据结构。(两种:空头链表,无空头链表)
- 结点:每一块内存。
- 数据:每一个结点里面,存放数据。
链表的操作:
(一)链表的头尾添加:
g_pEnd->pNext = pTemp;
g_pEnd = pTemp;
pTemp->pNext = g_pHead;
g_pHead = pTemp;
#include<stdio.h>
#include<stdlib.h>
struct Node
{
int a;//数据成员
struct Node* pNext;//指向下一个结点的指针
};
//链表头尾指针
struct Node* g_pHead = NULL;
struct Node* g_pEnd = NULL;
//创建链表,在链表中增加一个数据。(尾添加)
void AddListTill(int a)
{
//创建一个节点
struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node));
//对节点数据进行赋值
pTemp->a = a;
pTemp->pNext = NULL;
//将节点链接到链表上
if(NULL == g_pHead||NULL == g_pEnd) //链表里没有东西,新来的节点既是头也是尾
{
g_pHead = pTemp;
g_pEnd = pTemp;
}
else //正常情况,往尾巴上添加
{
g_pEnd->pNext = pTemp;
// 尾巴一直指向最后一个节点
g_pEnd = pTemp;
//逻辑顺序:先把新的节点接到尾上,再挪动尾结点,使他一直指向最后一个节点。
}
}
//创建链表,在链表中增加一个数据。(头添加)
void AddListHead(int a)
{
//创建一个节点
struct Node* pTemp = (struct Node*)malloc(sizeof(struct Node);
//节点数据赋值
pTemp->a = a;
pTemp->pNext = NULL;
//接在链表上
if(NULL == g_pHead)
{
g_pHead = pTemp;
g_pEnd = pTemp;
}
else
{
pTemp->pNext = g_pHead;
g_pHead = pTemp;
//逻辑顺序:先把新的结点接到头上,再挪动头结点,使他一直指向第一个节点。
}
}
int main()
{
int a[8] = {1,2,3,4,5,6,7,8};
int i;
g_pHead;
for(i = 0;i<8;i++){
AddListTill(a[i]);
AddListHead(a[i]);
}
return 0;
}
(二):链表的遍历:
1. 链表的全部遍历:
注:操作链表时,头指针不能变,可以定一个中间指针(pTemp)
int main()
{
int a[8] = {1,2,3,4,5,6,7,8};
int i;
g_pHead;
for(i = 0;i<8;i++){
AddListTill(a[i]);
//AddListHead(a[i]);
}
ScanList();
return 0;
}
void ScanList()
{
struct Node *pTemp = g_pHead;
while(pTemp != NULL)
{
pTemp = pTemp->pNext;
//逻辑:pTemp指向pTemp的后一个,直到遍历结束
printf("%d\n",pTemp->a);
}
}
2. 查询指定结点:
int main()
{
int a[8] = {1,2,3,4,5,6,7,8};
int i;
g_pHead;
for(i = 0;i<8;i++){
AddListTill(a[i]);
//AddListHead(a[i]);
}
struct Node *pFind = SelectNode(5);
if(pFind != NULL)
{
printf("%d\n",pFind->a);
}
else
{
printf("没找到!");
}
return 0;
}
struct Node* SelectNode(int a)
{
struct Node *pTemp = g_pHead;
while(pTemp != NULL)
{
if(a == pTemp->a)
{
return pTemp;
}
pTemp = pTemp->pNext;
}
//没找到
return NULL;
}
(三)链表清空:
一个节点一个节点的遍历,释放。
void FreeList()
{
//记录头,防止头被修改,丢内存
struct Node *pTemp = g_pHead;
while(pTemp != NULL)
{
struct Node* pt = pTemp;
pTemp = pTemp->pNext;
free(pt);
}
//头尾清空
g_pHead = NULL;
g_pEnd = NULL;
}
(四)指定位置插入节点:
void AddListRand(int index,int a)
{
//链表为空
if(NULL == g_pHead)
{
printf("链表没有节点\n");
return;
}
//找位置
struct Node* pt = SelectNode(index);
if(NULL == pt)
{
printf("没有指定节点\n");
return;
}
//有此节点
//给a创建节点
struct Node*pTemp = (struct Node*)malloc(sizeof(struct Node));
//给节点成员赋值
pTemp->a = a;
pTemp->pNext = NULL;
//链接到链表上
if(pt == g_pEnd)
{
//尾巴的下一个指向新的节点
g_pEnd->pNext = pTemp;
//新节点是最后一个,变成尾巴
g_pEnd = pTemp;
}
else
{
//先连
pTemp->pNext = pt->pNext;
//后断
pt->pNext = pTemp;
}
}
(五)头删除:
栈 = 头添加+头删除;
逻辑:
void DeleListHead()
{
//链表检测
if(NULL == g_pHead)
{
printf("链表为空,无需释放!\n");
return;
}
//记住旧的头
struct Node* pTemp = g_pHead;
//头的下一个节点变成新的头
g_pHead = g_pHead->pNext;
//释放旧的头
free(pTemp);
}
队列 = 头添加+尾删除(尾添加+头删除)
(六)尾删除:
逻辑:
void DeleListTail()
{
//链表检测
if(NULL == g_pHead)
{
printf("链表为空,无需释放!\n");
return;
}
//链表不为空,考虑链表元素个数
//链表有一个节点
if(g_pHead == g_pEnd)
{
free(g_pHead);
g_pHead = NULL;
g_pEnd = NULL;
}
//有多个节点
else
{
//找到尾巴前一个节点
struct Node* pTemp = g_pHead;
while(pTemp->pNext != g_pEnd)
{
pTemp = pTemp->pNext;
}
//找到了,删尾
//释放
free(g_pEnd);
//尾巴前移
g_pEnd = pTemp;
//尾的下一指针赋值NULL;
g_pEnd->pNext = NULL;
}
}
(七)删除指定节点:
删除中间节点的逻辑:
void DeleListRand(int a)
{
//链表判断
if(NULL == g_pHead)
{
printf("链表为空,无需释放!\n");
return;
}
//链表有东西,找这个节点
struct Node* pTemp = SelectNode(a);
if(NULL == pTemp)
{
printf("查无此节点\n");
return;
}
//找到了
//只有一个节点
if(g_pHead == g_pEnd)
{
DeleListHead();
}
//有两个节点
else if(g_pHead->pNext == g_pEnd)
{
if(g_pHead == pTemp)
{
DeleListHead();
}
else
{
DeleListTail();
}
}
//有多个节点
else
{
if(g_pHead == pTemp)
{
DeleListHead();
}
else if(g_pEnd == pTemp)
{
DeleListTail();
}
//删除中间节点
else
{
//找到要删除的节点的前一个节点
struct Node* pT = g_pHead;
while(pTemp->pNext != pTemp)
{
pT = pT->pNext;
}
//找到了
//链接
pT->pNext = pTemp->pNext;
//释放
free(pTemp);
}
}
}