顺序表的理解操作:点击打开链接
单链表:一种链式存储的线性表,用一组地址任意的存储单元存放线性表的数据元素,称存储单元为一个节点。(每个结点中只包含一个指针域)
链式的存储结构的特点:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)
单链表的结构:
1.对于任意一个数据元素a(i)来说,储存本身的数据.(这个域叫数据域)
2.存储一个下一个(后继)数据元素的信息(pNext)(这个域叫指针域)
这两部分信息组成数据元素a(i)的存储映像,称为结点。
单链表的结构:
typedef int DataType; typedef struct SNode { DataType data; //保存本身的信息 struct SNode *_pNext;//保存下个节点的地址 }SNode, *PNode;
代码部分:
list.h
#pragma once #include <stdio.h> #include <assert.h> #include <stdlib.h> typedef int DataType; typedef struct SNode { DataType data; //保存本身的信息 struct SNode *_pNext;//保存下个节点的地址 }SNode, *PNode; void SListInit(PNode* pHead);// 链表的初始化 void SListPushBack(PNode* pHead, DataType data);// 尾插 void SListPopBack(PNode* pHead);// 尾删 void SListPushFront(PNode* pHead, DataType data);// 头插 void SListPopFront(PNode* pHead);// 头删 PNode SListFind(PNode pHead, DataType data);// 在链表中查找值为data的元素,找到后返回值为data的结点 void SListInsert(PNode* pHead, PNode pos, DataType data);// 在pos位置插入值为data的结点 void SListErase(PNode* pHead, PNode pos);// 删除pos位置的结点 int SListSize(PNode pHead);// 获取链表中节点总数 int SListEmpty(PNode pHead);// 判断链表是否为空 void SListDestroy(PNode* pHead);// 销毁链表 void PrintfList(PNode pHead);//打印链表
list.c
#include "list.h" //初始化就是将链表头指针赋空, //注意这里要传头指针的地址才能改变头指针的值 void SListInit(PNode* pHead) { assert(pHead);//判断链表是否存在 *pHead = NULL; } //创建新节点 PNode BuyNewNode(DataType data) { PNode ptr = NULL; ptr = (PNode)malloc(sizeof(DataType)+sizeof(PNode)); if (NULL == ptr) { printf("BuyNewNode failed!!!\n"); return NULL; } //申请成功 ptr->data = data; ptr->_pNext = NULL; return ptr; } //打印链表 void PrintfList(PNode pHead) { PNode ptr = pHead; if (pHead == NULL) return; while (ptr) { printf("%d-->", ptr->data); ptr = ptr->_pNext; } printf("NULL\n"); } //尾插 void SListPushBack(PNode* pHead, DataType data) { PNode pCur = NULL; assert(pHead);//判断链表是否存在 if (*pHead == NULL)//判断链表是否为空 { *pHead = BuyNewNode(data);//空就让头节点指向新节点 return; } //1.先找到链表最后一个节点 pCur = *pHead; while (pCur->_pNext) { pCur = pCur->_pNext;//朝后走一步 } pCur->_pNext = BuyNewNode(data); } //尾删 void SListPopBack(PNode* pHead) { assert(pHead); PNode pPre = *pHead; PNode pCur = *pHead; if (*pHead == NULL) { printf("链表已空,删除失败!!!\n"); return; } //1.只有一个节点 if (pCur->_pNext == NULL) { free(*pHead); *pHead = NULL; return; } //2.有一个以上节点 while (pCur->_pNext) { pPre = pCur;//因为要找到倒数第二个节点,所以每走一步之前先保存 pCur = pCur->_pNext; } free(pPre->_pNext); pPre->_pNext = NULL; } //头插 void SListPushFront(PNode* pHead, DataType data) { PNode ptr = NULL; assert(pHead); //1.链表为空 if (NULL == *pHead) { *pHead = BuyNewNode(data); return; } //2.链表不为空 ptr = *pHead;//先保存第一个节点地址 *pHead = BuyNewNode(data);//头指针指向新节点 (*pHead)->_pNext = ptr;//新节点的_pNext指向原来的头节点 } //头删 void SListPopFront(PNode* pHead)// 头删 { assert(pHead); PNode ptr = NULL; if (NULL == pHead) { printf("链表已空,删除失败!!!\n"); return; } //1.只有一个节点 if ((*pHead)->_pNext == NULL) { free(*pHead); *pHead = NULL; return; } //2.有一个以上的节点 ptr = *pHead;//先保存头节点地址 *pHead = (*pHead)->_pNext;//头指针朝后走一步; free(ptr);//释放原头节点空间 } //查找为data的节点 PNode SListFind(PNode pHead, DataType data) { PNode ptr = pHead; if (NULL == pHead) { printf("对不起,为空链表!!!\n"); return NULL; } while ((ptr) && (ptr->data != data))//ptr中的data不是要找的且不为空就进入循环 { ptr = ptr->_pNext; } //1.ptr为空,证明找不到 if (NULL == ptr) { printf("对不起,找不到!!!\n"); return NULL; } else return ptr; } int SListSize(PNode pHead) { int count = 0; while (pHead) { pHead = pHead->_pNext; count++; } return count; } void SListInsert(PNode* pHead, PNode pos, DataType data) { assert(pHead); //1.链表为空 if (NULL == *pHead) { //1.如果链表为空,插入位置与头节点地址不相同,那么位置不合法 if (pos == *pHead) { *pHead = BuyNewNode(data); return; } else { printf("位置不合法,插入失败!!!\n"); return; } } //2.链表不为空 //(1)头插:pos与头节点地址相等 if (pos == *pHead) SListPushFront(pHead, data); //(2)pos与头节点位置不相等 else { PNode pPre = *pHead; PNode pCur = *pHead; while ((pCur) && (pCur->_pNext != pos)) { pCur = pCur->_pNext; } if (pCur == NULL) { printf("对不起,找不到该节点!!!\n"); return; } else { pCur->_pNext = BuyNewNode(data);//插入新节点 pCur->_pNext->_pNext = pos;//新节点链接pos处的节点 pos = pCur->_pNext;//pos指向新节点 } } } // 删除pos位置的结点 void SListErase(PNode* pHead, PNode pos) { assert(pHead); PNode ptr = *pHead; if (NULL == *pHead) { printf("链表已空,删除失败!!!\n"); return; } //1.只有一个节点 if ((*pHead)->_pNext == NULL) { if (*pHead == pos) { free(pos); *pHead = NULL; return; } else { printf("位置不合法,删除失败!!!\n"); return; } } //2.有一个以上节点 //(1)如果pos是头节点 if (pos == *pHead) { *pHead = (*pHead)->_pNext; free(pos); return; } //(2)不是头结点 while ((ptr) && (ptr->_pNext != pos) && (pos)) { ptr = ptr->_pNext; } if ((ptr == NULL) || (pos == NULL)) { printf("节点不存在,删除失败!!!\n"); return; } else { ptr->_pNext = pos->_pNext;//链接起pos的下个节点 free(pos); } } // 判断链表是否为空 int SListEmpty(PNode pHead) { if (pHead) return 1; return 0; } // 销毁链表 void SListDestroy(PNode* pHead) { assert(pHead); PNode ptr = *pHead; PNode pMsg = *pHead; while (ptr) { ptr = ptr->_pNext;//ptr朝后走 free(pMsg);//释放pMsg指向的空间 if (ptr) pMsg = ptr;//pMsg跟着ptr走 } *pHead = NULL; }
test.c
#include <windows.h> void TestList() { SNode SList; PNode pHead = &SList; SListInit(&pHead);// 链表的初始化 //SListEmpty(pHead);// 判断链表是否为空 //SListInsert(&pHead, pHead, 40); //PrintfList(pHead); //SListPushFront(&pHead, 0); //PrintfList(pHead); SListPushBack(&pHead, 5);//尾插 SListPushBack(&pHead, 10); SListPushBack(&pHead, 3); PrintfList(pHead); //SListPopBack(&pHead);//尾删 //PrintfList(pHead); //SListPushFront(&pHead, 0);//头插 ////PrintfList(pHead); ////SListPopFront(&pHead);//头删 //PrintfList(pHead); //// 在链表中查找值为data的元素,找到后返回值为data的结点 //SListFind(pHead, 3); //SListSize(pHead);// 获取链表中节点总数 //SListInsert(&pHead, pHead->_pNext->_pNext, 20);// 在pos位置插入值为data的结点 //PrintfList(pHead); //SListErase(&pHead, pHead->_pNext->_pNext);// 删除pos位置的结点 //PrintfList(pHead); //SListDestroy(&pHead);// 销毁链表 } int main() { TestList(); system("pause"); return 0; }