• 单链表——基本操作


    单链表结构定义

     1 //注意:所有对链表的结点操作都用变量节点pMove来完成,实现灵活遍历等使用
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <string.h>
     5 
     6 typedef char elemType;
     7 typedef struct NodeList
     8 {
     9 
    10     char element;//数据区域
    11     struct NodeList *next;//指针域
    12 }Node;//结点定义+变量定义

    初始化带头结点的单链表(均是对指针的定义,因此传入指针的地址,即地址的地址**)

     1 //1.初始化带头结点的单链表
     2 void InitialList(Node **pNode){
     3 
     4     //个人建议每一次malloc分配内存空间后,都要进行判断分配是否成功,也即判断是否为空;
     5     //此时的这个pNode就是一个头结点;
     6     //初始化成功后,其实相当于是一个正常的链表了;
     7     *pNode = (Node *)malloc(sizeof(Node));
     8     if (*pNode == NULL) {
     9         printf("
    %s函数执行,内存分配失败,初始化单链表失败
    ",__FUNCTION__);
    10     }else{
    11 
    12         (*pNode)->next = NULL;
    13         printf("
    %s带头结点的单链表初始化完成
    ",__FUNCTION__);
    14     }
    15 }

    创建带头结点的单链表

     1 //2.创建带头结点的单链表
     2 void CreateList(Node *pNode){
     3 
     4     /**
     5      *  就算一开始输入的数字小于等于0,带头结点的单链表都是会创建成功的,只是这个单链表为空而已,也就是里面除了头结点就没有其他节点了。
     6      */
     7     Node *pInsert;
     8     Node *pMove;
     9    int i;
    10     pInsert = (Node *)malloc(sizeof(Node));//需要检测分配内存是否成功 pInsert == NULL  ?
    11     memset(pInsert, 0, sizeof(Node));//用于为占内存大的数据结构如数组、结构体快速初始化
    12     pInsert->next = NULL;
    13     scanf("%c",&(pInsert->element));//先初始化一个首元节点pInsert
    14     
    15     pMove = pNode;//创建一个专门用来遍历结点的结点指针pMove,首先从头节点开始遍历
    16 
    17     for( i=0;i<5;i++)
    18     {
    19 
    20         pMove->next = pInsert;//将刚才初始化的首元节pInsert点连接到头节点pMove后面
    21         pMove = pInsert;//遍历结点指针pMove转移到首元节点上
    22 
    23         pInsert = (Node *)malloc(sizeof(Node)); //需要检测分配内存是否成功 pInsert == NULL  ?
    24         memset(pInsert, 0, sizeof(Node));
    25         pInsert->next = NULL;
    26         scanf("%c",&(pInsert->element));//又创建了新的结点
    27         
    28    }
    29 
    30 
    31     printf("
    %s带头结点的单链表创建成功
    ",__FUNCTION__);
    32 }

    memset功能函数:

    函数原型是:void *memset(void *s, int ch, size_t n);

    函数功能是:将s所指向的某一块内存中的前n个字节的内容全部设置为ch指定的ASCII值, 第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为指向s的指针,它是对较大的结构体或数组进行清零操作的一种最快方法。
     头文件是:<memory.h>或<string.h>
    memset函数通常用来对一块已经分配地址的内存进行初始化,并且通常初始化为0或者字符''(实际上是一样的)

    打印链表

     1 //3.打印带头结点的单链表
     2 void PrintList(Node *pNode){
     3     /**
     4      *  注意这里,如果单链表为空(只有一个头结点),我也让它打印(打印成功)。只是里面没有元素,打出来是空的而已,所以在控制台上就是一行空的;
     5      */
     6         Node *pMove;//创建遍历节点的结点变量
     7         pMove = pNode->next;//从首元结点(即头节点pNode后面->next的结点)开始遍历
     8         while (pMove != NULL)
     9         {
    10             printf("%c",pMove->element);
    11             pMove = pMove->next;//继续后移
    12         }
    13 
    14       
    15 }

    清除链表

     1 //4.清除链表表中的所有元素,即释放所有节点(除了头结点),使之成为一个空表
     2 void ClearList(Node *pNode){
     3 
     4     Node *pMove;
     5     pMove = pNode->next;//从首元结点开始遍历
     6     while (pMove != NULL) 
     7     {
     8 
     9         pNode->next = pMove->next;//每次删首元之前先重设置新的首元(即要删除首元的下一个节点)
    10         free(pMove);//删首元
    11         pMove = pNode->next;
    12     }
    13 
    14     printf("
    %s函数执行,清空带头结点的链表成功
    ",__FUNCTION__);
    15 }

    返回链表长度

     1 //5.返回带头结点的单链表的长度
     2 int SizeList(Node *pNode){
     3     /**
     4      *  当只有一个头结点的时候,size = 0;头节点不计算到链表长度中。
     5      */
     6     int i = 0;
     7     Node *pMove;
     8     pMove = pNode->next;//首元开始遍历
     9     while (pMove != NULL) {
    10         i++;
    11         pMove = pMove->next;
    12     }
    13 
    14     printf("
    %s带头结点的单链表h的长度为:%d
    ",__FUNCTION__,i);
    15 
    16     return i;
    17 }

    判断链表是否为空

     1 //6.判断带头结点的单链表是否为空,为空则返回1,否则返回0
     2 int IsEmptyList(Node *pNode){
     3     /**
     4      *  当只有一个头结点的时候,该链表就为空
     5      */
     6     if (pNode->next == NULL) {
     7         printf("
    %s带头结点的链表h为空
    ",__FUNCTION__);
     8         return 1;
     9     }
    10 
    11     printf("
    %s带头结点的链表h非空
    ",__FUNCTION__);
    12 
    13     return 0;
    14 }

    查找具体位置节点元素

     1 //7.返回单链表中第pos个结点中的元素,若返回-1,表示没有找到
     2 int GetElement(Node *pNode,int pos){
     3 
     4     int i = 1;
     5 
     6     Node *pMove;
     7     pMove = pNode->next;//首元结点开始
     8 
     9     while (pMove != NULL) //尾结点之前
    10     {
    11         if (i == pos)
    12         {
    13 
    14             printf("
    %spos=%d位置的值是%c
    ",__FUNCTION__,pos,pMove->element);
    15             return pMove->element;
    16         }
    17 
    18         i++;
    19         pMove = pMove->next;
    20     }
    21 
    22     printf("
    %s函数执行,在pos=%d位置没有找到值
    ",__FUNCTION__,pos);
    23     return -1;
    24 }

    
    

    查找给定元素节点位置

     1 //8.从单链表中查找具有给定值x的第一个元素,若查找成功则返回该结点data域的存储地址,否则返回NULL
     2 elemType* GetElemAddr(Node *pNode,char x){
     3 
     4     Node *pMove;
     5     pMove = pNode->next;
     6 
     7     while (pMove != NULL) {
     8         if (pMove->element == x) {
     9             printf("
    %s查找到x=%c的内存地址为:0x%x
    ",__FUNCTION__,x,&(pMove->element));
    10             return &(pMove->element);
    11         }
    12         pMove = pMove->next;
    13     }
    14 
    15     printf("
    %s函数执行,在带头结点的单链表中没有找到x=%d的值,无法获得内存地址
    ",__FUNCTION__,x);
    16 
    17     return NULL;
    18 }

    修改节点元素

     1 //9.把单链表中第pos个结点的值修改为x的值
     2 Node* ModifyElem(Node *pNode,int pos,int x){
     3 
     4     int i = 1;
     5     Node *pMove;
     6     pMove = pNode->next;
     7     while (pMove != NULL) {
     8         if (i == pos) {
     9             pMove->element = x;
    10             printf("
    %s函数执行,把pos=%d位置的值改为%d成功
    ",__FUNCTION__,pos,x);
    11             return pNode;
    12         }
    13         i++;
    14         pMove = pMove->next;
    15     }
    16     printf("
    %s函数执行,链表为空或者输入pos值非法,修改值失败
    ",__FUNCTION__);
    17 
    18     return pNode;
    19 }

    头插法(常用于向链表中添加结点元素)

     1 //10.向单链表的表头插入一个元素
     2 Node *InsertHeadList(Node *pNode,int x)
     3 {
     4 
     5      Node *pInsert;
     6     pInsert = (Node *)malloc(sizeof(Node));
     7     memset(pInsert, 0, sizeof(Node));
     8     pInsert->element = x;
     9 
    10     pInsert->next = pNode->next;
    11     pNode->next = pInsert;
    12 
    13     printf("%s在表头插入元素%d成功
    ",__FUNCTION__,x);
    14     return pNode;
    15 }

    尾插法

     1 // 11.向单链表的末尾添加一个元素
     2 Node *InsertTailList(Node *pNode,int x){
     3 
     4     Node *pMove;
     5     Node *pInsert;
     6    
     7     pInsert = (Node *)malloc(sizeof(Node));
     8     memset(pInsert, 0, sizeof(Node));
     9     pInsert->element = x;
    10     pInsert->next = NULL;//先为要插入的元素创建结点,由于差在尾部所以新的节点指针域为空指针NULL(比以往多了一步)
    11 
    12     pMove = pNode;
    13     while (pMove->next != NULL)//找尾指针
    14     {
    15         pMove = pMove->next;
    16     }
    17     pMove->next = pInsert;
    18 
    19     
    20 
    21     return pNode;
    22 }

    删除元素

     1 //12.从单链表中间删除元素
     2 Node *DeleteRand(Node *pNode,int index)
     3 {
     4     int e;
     5     Node *pMove;
     6     Node *q;
     7     int i;
     8     pMove = pNode;
     9     
    10     for(i=0;i<index-1;i++)
    11     {
    12         pMove=pMove->next;
    13     }
    14     q=pMove->next;
    15     e=q->element;
    16     pMove->next=q->next;
    17     
    18     free(q);
    19     printf("
    %s在表间第%d位置删除元素成功
    ",__FUNCTION__,index);
    20     
    21     return pNode;
    22 }

    插入元素

     1 //13.向链表中间插入一个元素
     2 Node *InsertRand(Node *pNode,int index,int a)
     3 {
     4     Node *pInsert;
     5     Node *pMove;
     6     int i;
     7     
     8     pInsert = (Node *)malloc(sizeof(Node));
     9     memset(pInsert, 0, sizeof(Node));
    10     pInsert->element = a;
    11     
    12     
    13     pMove = pNode;
    14     
    15     
    16     for(i=0;i<index-1;i++)
    17     {
    18         pMove=pMove->next;
    19     }
    20     pInsert->next=pMove->next;
    21     pMove->next=pInsert;
    22     printf("
    %s在表间第%d位置插入元素%c成功
    ",__FUNCTION__,index,a);
    23     ;
    24     return pNode;
    25 }    

    主函数测试(注意用头插法输入元素)

     1 int main(int argc, const char * argv[])
     2 {
     3 
     4     Node *pList;
     5 
     6     InitialList(&pList);
     7 
     8    InsertTailList(pList,'a');
     9    InsertTailList(pList,'b');
    10    InsertTailList(pList,'c');
    11    InsertTailList(pList,'d');
    12    InsertTailList(pList,'e');
    13    PrintList(pList);
    14     SizeList(pList);
    15 
    16     IsEmptyList(pList);
    17 
    18     GetElement(pList, 3);
    19 
    20     GetElemAddr(pList, 'a');
    21 
    22     InsertRand(pList,4,'f');
    23      PrintList(pList);
    24     
    25      DeleteRand(pList,3);
    26      PrintList(pList);
    27 
    28     
    29    
    30     
    31 
    32     ClearList(pList);
    33     PrintList(pList);
    34 
    35     return 0;
    36 }
    37 
    38    

  • 相关阅读:
    Java代码:response压缩响应
    SpringBoot框架:第一章:基础配置和介绍
    asp.net 发送email
    .NET环境下水晶报表使用总结
    ASP.net(c#)生成条形码
    表格操作类(添加,删除,排序,上移,下移)
    NET email
    C#如何打印条形码EAN13码
    在asp.net中备份还原SQL Server数据库
    配置SQL2000数据库发送邮件
  • 原文地址:https://www.cnblogs.com/YOLO-in-the-sun/p/12877780.html
Copyright © 2020-2023  润新知