数据结构(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("\n");
 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("\n");
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("\n");
8 }

猜你喜欢

转载自www.cnblogs.com/jiangyu0331/p/11668755.html