不连续的存储结构
包含n个节点,每个节点包含数据域和指针域,指针域指向下一个节点
下述链表指单链表。。
头结点只有指针域,是整个链表入口,相关的遍历查询都需要从头指针开始,头结点数据域没有意义为一个随机值
#include "stdafx.h"
#include <stdio.h>
#include<iostream>
using namespace std;
//创建
typedef struct student
{
int data;
student * Next;
}Node,*pNode;
Node* CreateList(void)
{
int len;
int val;
pNode pEnd=NULL;
pNode pHead = (Node*)malloc(sizeof(Node));
pEnd = pHead; //尾指针先指向头节点,在此基础上增加新节点
pEnd->Next = NULL; //此时只有一个头结点,头结点的next指针指向NULL
printf("please input the len:");
scanf("%d",&len);
for(int i=0;i<len;i++)
{
printf("请输入第 %d 个节点的数据:", i + 1);
scanf("%d",&val);
pNode pNew =(Node*)malloc(sizeof(Node)); //给新节点分配内存
pNew->data = val; //给新节点赋值
pNew->Next=NULL; //新节点下一个先为空
pEnd->Next= pNew; //尾指针的指针域指向新增加的节点
pEnd = pNew; //尾指针指向新节点,新节点变成尾节点
}
printf("list create success");
return pHead;
}
//遍历
void printlist(pNode phead)
{
pNode p = phead->Next;
while(p)
{
cout<<p->data<<endl; //通过尾节点的指针域是否为空判断链表是否已结束
p =p->Next;
}
}
void main()
{
pNode mHead = CreateList();
printlist(mHead);
cin.get();
cin.get();
}
其余啥的删除、反转等操作均在此基础上进行,有点绕但并不复杂,F10、F11多单步运行就行
增加查询与删除接口:
//查询
int getlistIndex(pNode pHead,int data)
{
pNode p = pHead->Next;
int index = 0;
while(p)
{
if(data == p->data)
{
break;
}
else
{
index++;
p =p->Next;
}
}
if(!p)
{
cout<<"there is no data in the list"<<endl;
return -1;
}
else
{
return (index+1);
}
}
//删除整个list
void deletelist(pNode pHead)
{
pNode p = pHead->Next;
free(pHead); //删除头指针
while(p)
{
pNode tmp = p ->Next;
free(p);
p = tmp;
}
cout<<"delete all list successed"<<endl;
}
这里主要记录一下头指针的删除,之前从其他地方看的时候是没有这一步的,后来把main函数改成这样后
void main()
{
pNode mHead = CreateList();
deletelist(mHead);
pNode p1 = (Node*)malloc(sizeof(Node));
//printlist(mHead);
//int index = getlistIndex(mHead,5);
//cout << "5 in listIndex is :"<<index<<endl;
cin.get();
cin.get();
}
看了一下,无论我们在deletelist中还是在main函数中去释放这个头指针的空间,都是可以并且有必要的,因为如果释放,新创建的p1开辟的空间就可以使用已经被释放的堆空间,单步调试时也确实如此,而如果未释放,p1将去开辟新的空间,而我们以为删除掉了list,实际却留下了多余的垃圾,所有无论我们什么时候去malloc或者new去占掉了内存,都需要去对应的free或者delele掉它,而如果指向这片空间的指针为全局指针,还需要将指针置空,避免野指针的产生。