C语言整理-双向链表和单项链表那些事

C语言整理-双向链表和单项链表那些事,第1张

链表一般细分为:

1、不带头节点的单链表
2、带头节点的单链表
3、不带头结点的双链表
4、带头结点的双链表
5、带头结点的双向循环链表

其具体的实现过程可以由下图表示:

头指针:

  1. 头指针是指链表指向第一个结点的指针,若链表有头结点,则是指向头结点的指针

  2. 头指针具有标识作用,所以常用头指针冠以链表的名字

  3. 无论链表是否为空,头指针均不为空,头指针是链表的必要元素

头节点:

  1. 头结点是为了 *** 作的统一和方便而设立的,放在第一元素(首元节点)的结点之前,其数据域一般无意义(也可存放链表的长度)

  2. 有了头结点,对在第一元素结点前插入结点和删除第一结点,其 *** 作与其它结点的 *** 作就统一了

  3. 头结点不一定是链表必须要素

双链表实现

#include
#include

typedef struct node //定义一个结构体,里面包含链表的一些格式定义!
{
 int data; //"数据域" 保存数据元素
 struct node * next; //保存下一个数据元素的地址
 struct node * prev; //保存上一个数据元素的地址
}Node;//将这个结构体另命名为node 

//创建表头表示链表 
Node* creatList()//这个部分创造的节点也就是头指针!
{
 Node * HeadNode = (Node *)malloc(sizeof(Node));//申请链表内存!
 //初始化,自己指向自己 
 HeadNode->next = HeadNode->prev = HeadNode;
 return HeadNode;
}

//创建节点 
Node* creatNode(int data)
{
 Node* newNode = (Node *)malloc(sizeof(Node));
 //初始化
 newNode->data = data;//此处创造一个单独节点,还有做任何 *** 作,所以前后指针都指向NULL
 newNode->next = NULL;
 newNode->prev = NULL;
 return newNode;
}

//遍历链表
void printList(Node *headNode)
{
 //双向链表不光可以用 next 打印,也可以用 prev 进行打印
 //next指针打印:先进后出   
 //prev指针打印:先进先出 
    Node *p = headNode -> next;//定义一个指针p,指向头指针的下一个节点!
    while(p != headNode){   //判断p所指向的节点是不是头指针,如果不是依次向后轮,如果最终指向头
                            //指针,那就说明此时p指向的刚好是最后一个节点,遍历完毕
        printf("%d\t",p->data);
        p = p -> next;
    }
    printf("\n");
}


void insertNodebyHead(Node *headNode,int data)//插入节点:头插法
{
 Node *newNode = creatNode(data); //创建插入的节点 ,叫做nodeNode
                                  //注意顺序,赋值会改变指针指向,因此要先连后断 
 newNode -> prev = headNode;      //新节点的的前指针指向头指针
 newNode -> next = headNode -> next;//新节点的后指针指向头指针后面的节点
 headNode ->next->prev = newNode;//头指针后面的节点的前指针指向新节点
 headNode -> next =  newNode;    //头指针指向新节点
}


void insertNodebyTail(Node *headNode,int data)//插入节点:尾插法 
{
 Node *newNode = creatNode(data); //创建插入的节点
   
 Node *lastNode = headNode;        //第一步:首先要找到最后一个节点,定义一个尾节点指针,
                                   //先指向头指针,然后一一比对,找出尾节点
 while(lastNode->next != headNode) //因为尾节点的后指针指向的是头指针,所以只需要判断这个节点
                                   //是不是指向头指针,只要指向,那就说明这个节点就是尾节点
 {
  lastNode = lastNode->next;//往下走 
 }
 
 //注意顺序,
 headNode->prev =  newNode;  //头指针指向新节点(插入后就变成了尾节点)
 newNode->next = headNode;   //新节点(插入后就变成了尾节点)的后指针指向头指针
 lastNode->next = newNode;   //原尾指针的后指针指向新节点(现尾节点)
 newNode->prev = lastNode;   //新节点(插入后就变成了尾节点)的前指针指向原节点
}


void deleteNodebyAppoin(Node *headNode,int posData)//删除节点
{
 // posNode 想要删除的节点,从第一个节点开始遍历 
 // posNodeFront 想要删除节点的前一个节点 
    Node *posNode = headNode -> next;
    Node *posNodeFront = headNode;
    
 if(posNode == NULL)
  printf("链表为空,无法删除");
 else{
  while(posNode->data != posData)
  {
   //两个都往后移,跟着 posNodeFront 走 
   posNodeFront = posNode;  
   posNode = posNodeFront->next;
   if (posNode->next == headNode)
   {
    printf("没有找到,无法删除");
    return; 
   }
  }
  //找到后开始删除 
  posNodeFront->next = posNode->next;
  posNode->next->prev = posNodeFront;
  free(posNode);
 } 
}

int main()
{
 Node* List = creatList();
 
 insertNodebyHead(List,1); 
 insertNodebyHead(List,2); 
 insertNodebyHead(List,3);  
 printList(List);
 
 insertNodebyTail(List,0); 
 printList(List);
 
 deleteNodebyAppoin(List,2);
 printList(List);
 
 return 0;
}

结果:

C语言高级-链表、状态机、多线程_钟浩森的博客-CSDN博客

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/915297.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-16
下一篇2022-05-16

发表评论

登录后才能评论

评论列表(0条)

    保存