首先介绍一些链表的基本知识,然后通过程序实现链表操作的基本功能,增删改查,打印等等操作,并模块化来深化这部分知识点。
链表基础知识
1、由一张内存图展开
(1)链表有一个“头指针”变量,如果不提供“头指针”,整个链表都无法访问;
(2)链表的每个元素成为“结点”,每个结点包括数据和下一个结点的地址。末尾的结点地址部分为NULL(空地址);
(3)链表中个元素在内存中的地址可以是不连续的;
2、链表的建立
(1)静态链表:所有结点在程序中定义的,不是临时开辟的,也不能用完后释放;
(2)动态链表:在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。
3、链表的基本操作
写这个代码的时候,中间因为一个while写成了if真是最后测试一直错误,真是醉了!!!奉上完整代码。有错的地方请指正~测试下来是没错的。
#include <stdio.h>
#include <stdlib.h>
typedef int Datatype; //如果存其他类型的数据可以在此处直接修改
typedef struct node {
Datatype data;
struct node *next;
}Node;
//创建结点
Node* creatNode(Datatype data) {
Node* p = NULL;
p = (Node*)malloc(sizeof(Datatype)); //申请内存
if (p == NULL) { //安全检查
return NULL;
}
p->data = data; //赋值
p->next = NULL;
return p;
}
//打印链表
void printList(Node* head) {
Node* p = head;
if (head == NULL) {
return;
}
while(p != NULL) {
printf("%d\n",p->data);
p = p->next;
}
return;
}
//在一个结点后插入新结点
int insertNodeBehind(Node* p,Node* pnew) {
if (p == NULL || pnew == NULL) {
return -1;
}
if (p->next != NULL) {
pnew->next = p->next;
p->next = pnew;
}
else {
p->next = pnew;
}
/*其实此处直接写
pnew->next = p->next;
p->next = pnew;
就可以了,因为若p->next = NULL则pnew->next = NULL*/
return 0;
}
//结点后插入一个数据
int insertDataBehind(Node *p,Datatype data) { Node* pnew = NULL; if (p == NULL) { return -1; }
pnew = creatNode(data);
insertNodeBehind(p,pnew);
return 0;
}
//返回最后末尾结点的地址
Node* findListTail(Node* phead) {
if (phead == NULL) {
return NULL;
}
while (phead->next != NULL) {
phead = phead->next;
}
return phead;
}
//插入数据到链表的末尾,**是因为可能会涉及修改头指针,在没有结点的情况下
int listInsertDataAtTail(Node** phead,Datatype data) {
Node *p = NULL;
if (phead == NULL) {
return -1;
}
if (*phead == NULL) {
*phead = creatNode(data);
return 0;
}
p = findListTail(*phead);
insertDataBehind(p,data);
return 0;
}
//删除后一个结点
int deleteNodeBehind(Node* p) {
Node* temp = NULL;
if (p == NULL) {
return -1;
}
if (p->next == NULL) {
return 1;
}
temp = p->next;
p->next = p->next->next;
free(temp);
return 0;
}
//返回数据为data的结点的地址
Node* findNode(Node* head,Datatype data) {
Node* p = NULL;
if (head == NULL) {
return NULL;
}
p = head;
while (p->data != data) {
if (p->next != NULL) {
p = p->next;
}
else {
return NULL; //没找到该数据为data的结点
}
}
return p;
}
//改数据
int listChangeData(Node* head,Datatype oldData,Datatype newData) {
Node* p = NULL;
if (head == NULL) {
return -1;
}
p = findNode(head, oldData);
p->data = newData;
return 0;
}
//返回数据为data的结点的前一个结点的地址
Node* findPrevNode(Node *head,Datatype data) {
Node* p = NULL;
if (head == NULL) {
return NULL;
}
p = head;
while (p->next != NULL) {
if (p->next->data == data) {
return p;
}
else {
p = p->next;
}
}
return NULL;
}
//删除链表中第一个数据为data的结点
int listDeleteData(Node** phead,Datatype data) { Node* p = NULL; Node* temp = NULL; if (phead == NULL || *phead == NULL) { return -1; }
if ((*phead)->data == data) { temp = (*phead); (*phead) = (*phead)->next; free(temp); return 0; }
p = findPrevNode(*phead, data);
deleteNodeBehind(p);
free(temp);
return 0;
}
//销毁链表
int listDestroy(Node **phead) {
if (phead == NULL || (*phead) == NULL) {
return 0;
}
while ((*phead)->next != NULL) { deleteNodeBehind(*phead); } (*phead) = NULL; free(*phead); //不知道此处有没有错误! return 0; }
int main(int argc, const char * argv[]) {
// 创建结点,查尾,增加结点
Node* p = NULL;
listInsertDataAtTail(&p, 1); //调用了creatNode,findListTail,insertNodeBehind
printList(p);
listInsertDataAtTail(&p, 2);
listInsertDataAtTail(&p, 3);
listInsertDataAtTail(&p, 4);
listInsertDataAtTail(&p, 5);
printf("已有节点:1-2-3-4-5\n");
printList(p);
// 删除
// printf("删除1后面结点\n");
// listDeleteData(&p, 1);
// listDeleteData(&p, 3);
// printList(p);
// 修改
printf("修改2为20000\n");
listChangeData(p, 2, 20000);
printList(p);
listDestroy(&p);
printList(p);
return 0;
}
output:
1
已有节点:1-2-3-4-5
1
2
3
4
5
修改2为20000
1
20000
3
4
5
终于好了~休息了,休息了~晚安,虽然看客还不多,不过慢慢来,会坚持写下去的,最近这样写下来收获还是很大的,毕竟要给别人看(虽然没人哈哈哈哈),有些知识点也补漏了一些~继续加油!
等有人了,多提提意见各位大牛~谢啦