zoukankan      html  css  js  c++  java
  • 数据结构(3)-----链表

    一、线性结构:
      数组:
      (1) 一片连续的内存空间 不能是断开的
      (2) 因为是连续的内存空间 才可以使用下标来访问
        arr[i] === *(arr+i)
        访问效率非常高
      (3) 在数据前面插入和删除的效率都比较低 (需要移动数据)

      链表:
      (1) 内存是不连续的
      (2) 访问效率比较低 因为需要从第一个元素开始遍历
      (3) 在任何地方插入和删除的效率都比较高 (只需要改变指针的值)

    二、单向链表

      单向链表的节点:节点元素+下一个节点的地址

    1 typedef int T;
    2 //单向链表的节点
    3 typedef struct SNode{
    4     T data;             //节点元素
    5     struct SNode *next; //下一个节点的地址   指向下一个节点
    6 }SNode;
    7 
    8 //定义单向链表类型 SLink
    9 typedef struct SNode *  SLink;

      1.初始化链表 

        申请头节点的动态内存 头节点不保存数据 也没有下一个节点的地址(NULL)

    1 void init(SLink* plink){
    2     *plink = malloc(sizeof(SNode));    
    3     (*plink)->next = NULL;
    4 }
    5 SLink createSLink(){
    6     SNode * node = malloc(sizeof(SNode));
    7     node->next = NULL;
    8     return node;
    9 }

      2.判断链表是否为空

    1 bool isEmpty(SLink link){
    2     return link->next == NULL;    
    3 }

      3.在头部插入一个节点 将要存储的数据加入

    1 void insertFront(SLink link,T data){
    2     SNode *node = malloc(sizeof(SNode));
    3     node->data = data;
    4     node->next = link->next;
    5     link->next = node;
    6 }

      4.遍历链表

     1 void travel(SLink link){
     2     if(link != NULL){
     3         SNode *node = link->next;
     4         while(node != NULL){
     5             printf("%d ",node->data);
     6             node = node->next;
     7         }
     8         printf("
    ");
     9     }
    10 }

      5.链表数据个数

    1 size_t size(SLink link){
    2     SNode *node = link->next;    
    3     size_t cnt = 0;
    4     while(node != NULL){
    5         cnt++;
    6         node = node->next;
    7     }
    8     return cnt;
    9 }

      6.获得index下标位置节点的前一个节点

    1 static SNode *getPrevNode(SLink link,size_t index){
    2     SNode *node = link;
    3     for(int i=0;i<index;i++){
    4         node = node->next;    
    5     }
    6     return node;
    7 }

      7.在指定的下标位置插入一个元素

     1 void insert(SLink link,size_t index,T data){
     2     if(index>size(link)){
     3         return;
     4     }
     5     //找到index下标节点的前一个节点
     6     SNode *prevNode = getPrevNode(link,index);
     7     SNode *currNode = malloc(sizeof(SNode));
     8     currNode->data = data;
     9     currNode->next = prevNode->next;
    10     prevNode->next = currNode;
    11 }

      8.根据下标删除元素

    1 void deleteByIndex(SLink link,size_t index){
    2     if(index>=size(link)){
    3         return;    
    4     }    
    5     SNode *prevNode = getPrevNode(link,index);
    6     SNode *currNode = prevNode->next;
    7     prevNode->next = prevNode->next->next;
    8     free(currNode);//释放内存
    9 }

      9.清空链表中的元素

    1 void clear(SLink link){
    2     SNode *node = link->next;
    3     while(node != NULL){
    4         SNode *next = node->next;//记录当前节点的后一个节点位置
    5         free(node);//释放当前节点的内存
    6         node = next;//指向下一个节点
    7     }
    8     link->next = NULL;
    9 }

      10.销毁链表

    1 void destroy(SLink *plink){
    2     clear(*plink);
    3     free(*plink);
    4     *plink = NULL;
    5 }

      11.删除链表中第一个数据是data的节点

     1 void deleteData(SLink link,T data){
     2     SNode *prevNode = link;
     3     SNode *currNode = link->next;
     4     while(currNode != NULL){
     5         if(currNode->data == data){
     6             prevNode->next = currNode->next;
     7             free(currNode);
     8             return;
     9         }    
    10         prevNode = currNode;
    11         currNode = currNode->next;
    12     }
    13 }

      12.删除链表中所有数据是data的节点

     1 void deleteAllDatas(SLink link,T data){
     2     SNode *prevNode = link;//头节点
     3     SNode *currNode = link->next;
     4     while(currNode != NULL){
     5         if(currNode->data == data){
     6             prevNode->next = currNode->next;
     7             free(currNode);
     8             currNode = prevNode->next;
     9             continue;
    10         }    
    11         prevNode = currNode;
    12         currNode = currNode->next;
    13     }
    14 }

      13.根据下标修改链表中的元素

    1 void modify(SLink link,size_t index,T data){
    2     if(index>=size(link)){
    3         return;
    4     }    
    5     SNode *node = getPrevNode(link,index+1);
    6     node->data = data;
    7 }

      14.根据下标获取元素

        如果index>=size(link)都将引发错误

     1 T getDataByIndex(SLink link,size_t index){
     2     /*
     3     if(index>=size(link)){
     4         return -1;    
     5     }
     6     */
     7     SNode *node = link->next;
     8     for(int i=0;i<index;i++){
     9         node = node->next;    
    10     }
    11     return node->data;
    12 }

      15.链表逆序  ---笔试题概率最大的编程题

     1 void reverse(SLink link){
     2     //if(link==NULL){return;}
     3     //没有节点或者只有一个节点时 不需要做任何事情
     4     if(link->next == NULL || link->next->next == NULL){
     5         return;    
     6     }
     7     SNode *prevNode = link->next;//第一个节点  前面节点
     8     SNode *currNode = prevNode->next;//第二个节点
     9     while(currNode != NULL){
    10         SNode *nextNode = currNode->next;//记录当前节点的后一个节点
    11         currNode->next = prevNode;//让当前节点的next指向之前的前节点
    12         prevNode = currNode;//前节点变 指向现在当前的节点
    13         currNode = nextNode;//当前的节点 指向 下一个节点
    14     }
    15     link->next->next = NULL;//让原来的第一个节点的next指向NULL
    16     link->next = prevNode;//让头节点next指向原来最后的那个节点
    17 }

    三、双向链表

     1 typedef int T;
     2 
     3 typedef struct DNode{
     4     T data;
     5     struct DNode *prev;
     6     struct DNode *next;
     7 }DNode;
     8 
     9 typedef struct DLink{
    10     //头尾结点不存储数据
    11     DNode *head;//指向头节点
    12     DNode *tail;//指向尾节点
    13 }DLink;

      1.初始化链表

      申请头节点和尾节点的动态内存 

      双向链表的头节点prev指向NULL next指向尾节点  尾节点prev指向头节点 next指向NULL

    1 void init(DLink *dlink){
    2     dlink->head = malloc(sizeof(DNode));
    3     dlink->tail = malloc(sizeof(DNode));
    4     dlink->head->prev = NULL;
    5     dlink->head->next = dlink->tail;
    6     dlink->tail->prev = dlink->head;
    7     dlink->tail->next = NULL;
    8 }

      2.清空链表所有节点

     1 void clear(DLink *dlink){
     2     DNode *node = dlink->head->next;
     3     while(node != dlink->tail){
     4         DNode *next = node->next;
     5         free(node);
     6         node = next;
     7     }
     8     dlink->head->next = dlink->tail;
     9     dlink->tail->prev = dlink->head;
    10 }

      3.销毁链表

    1 oid destroy(DLink *dlink){
    2     clear(dlink);
    3     free(dlink->head);
    4     dlink->head = NULL;
    5     free(dlink->tail);
    6     dlink->tail = NULL;
    7 }

      4.链表是否为空

    1 bool isEmpty(DLink dlink){    
    2     return dlink.head->next == dlink.tail && dlink.head == dlink.tail->prev;
    3 }

      5.链表元素个数

    1 size_t size(DLink dlink){
    2     DNode *node = dlink.head->next;
    3     size_t cnt = 0;
    4     while(node != dlink.tail){
    5         cnt++;
    6         node = node->next;
    7     }
    8     return cnt;
    9 }

      6.从头部插入一个元素

      需要创建新的节点,申请新的动态内存

      头节点的prev还是指向NULL,next指向新节点
      尾节点的next还是指向NULL,prev指向新节点
      新节点的next指向尾节点,prev指向头节点

    1 void insertFront(DLink dlink,T data){
    2     DNode *node = malloc(sizeof(DNode));
    3     node->data = data;
    4     node->next = dlink.head->next;
    5     node->prev = dlink.head;
    6     dlink.head->next->prev = node;
    7     dlink.head->next = node;
    8 }

      7.获得上一个节点

    1 static DNode * getPrevNode(DLink dlink,size_t index){
    2     DNode *node = dlink.head;
    3     for(int i=0;i<index;i++){
    4         node = node->next;    
    5     }
    6     return node;
    7 }

      8.根据下标插入一个元素

     1 void insert(DLink dlink,size_t index,T data){
     2     if(index > size(dlink)){
     3         return;    
     4     }
     5     DNode *prevNode = getPrevNode(dlink,index);
     6     DNode *node = malloc(sizeof(DNode));
     7     node->data = data;
     8     node->next = prevNode->next;
     9     node->prev = prevNode;
    10     prevNode->next->prev = node;
    11     prevNode->next = node;
    12     
    13 }

      9.根据下标删除一个元素

    1 void deleteByIndex(DLink dlink,size_t index){
    2     if(index >= size(dlink)){
    3         return;    
    4     }
    5     DNode *currNode = getPrevNode(dlink,index+1);
    6     currNode->next->prev = currNode->prev;
    7     currNode->prev->next = currNode->next;
    8     free(currNode);
    9 }

      10.从头部开始遍历链表

    1 void travelFront(DLink dlink){
    2     DNode *node = dlink.head->next;
    3     while(node != dlink.tail){
    4         printf("%d ",node->data);    
    5         node = node->next;
    6     }
    7     printf("
    ");
    8 }

      11.从尾部开始遍历链表

    1 void travelBack(DLink dlink){
    2     DNode *node = dlink.tail->prev;
    3     while(node != dlink.head){
    4         printf("%d ",node->data);
    5         node = node->prev;
    6     }
    7     printf("
    ");
    8 }
  • 相关阅读:
    Dbzoj#3188. [Coci 2011]Upit
    P1903 [国家集训队]数颜色 带修改莫队板子
    P2045 方格取数加强版
    P1402 酒店之王
    P4151 [WC2011]最大XOR和路径
    Orz YYB!
    Atcoder2167 Blackout
    P2939 [USACO09FEB]改造路Revamping Trails
    博弈论简单入门sb总结
    P3592 [POI2015]MYJ
  • 原文地址:https://www.cnblogs.com/jiangyu0331/p/11668755.html
Copyright © 2011-2022 走看看