c/c++ 線性表之雙向迴圈連結串列

小石王發表於2018-06-28

c/c++ 線性表之雙向迴圈連結串列

線性表之雙向迴圈連結串列

不是存放在連續的記憶體空間,連結串列中的每個節點的next都指向下一個節點,每個節點的before都指向前一個節點,最後一個節點的下一個節點不是NULL,是頭節點。

真實的第一個節點是頭節點,頭節點不存放資料,單純為了編寫程式方便。但是下面註釋裡寫的【第一個節點】的含義是頭節點的下一節點,也就是真實存放資料的第一個節點。

下面的程式碼實現了以下功能

函式 功能描述
push_back 從連結串列的最後插入節點
push_front 從連結串列的起始插入節點
show_list 列印出連結串列裡每個節點的值
pop_back 刪除連結串列最後一個節點
pop_front 刪除連結串列起始節點
insert_val 在合適的位置插入一個節點;
比如原來的連結串列:1->3->NULL,當要插入的節點的值為2的時候,就會在1和3之間插入這個節點,插入後的連結串列:1->2->3->NULL
find 查詢指定的節點
length 返回連結串列中節點的個數
delete_val 刪除指定的節點
sort 排序,重新排列節點
resver 按倒序,重新排列節點
clear 釋放除了頭節點之外的所有節點所佔用的記憶體空間
destroy 釋放所有節點的所佔用的記憶體空間,包括頭節點

whileshuangnode.h

#ifndef __WHILESHUANGNODE__
#define __WHILESHUANGNODE__

#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <memory.h>
#include <stdbool.h>

#define ElemType int

typedef struct Node{
  ElemType data;
  struct Node* before;
  struct Node* next;
}Node;

typedef struct NodeList{
  Node*  first;
  Node*  last;
  size_t size;
}NodeList;

void init(NodeList*);
void push_back(NodeList*, ElemType);
void push_front(NodeList*, ElemType);
void pop_back(NodeList*);
void pop_front(NodeList*);
void show_list(NodeList*);
void insert_val(NodeList*, ElemType);
Node* find(NodeList*, ElemType);
void delete_val(NodeList*, ElemType);
void sort(NodeList*);
void sort1(NodeList*);
void resver(NodeList*);
void resver1(NodeList*);
void resver2(NodeList*);
void clear(NodeList*);
void destroy(NodeList*);

#endif

whileshuangnode.c

#include "whileshuangnode.h"

void init(NodeList* list){
  list->first = (Node*)malloc(sizeof(Node));
  list->last = list->first;
  list->first->before = list->last;
  list->last->next = list->first;
  list->size = 0;
}

Node* create_node(ElemType val){
  Node* node = (Node*)malloc(sizeof(Node));
  assert(NULL != node);
  node->data = val;
  node->before = NULL;
  node->next = NULL;
  return node;
}
void push_back(NodeList* list, ElemType val){
  Node* p = create_node(val);

  p->before = list->last;
  p->next = list->first;
  
  list->first->before = p;
  list->last->next = p;

  list->last = p;
  
  list->size++;
}

void push_front(NodeList* list, ElemType val){
  Node* p = create_node(val);

  //設定p的before和next
  p->before = list->first;
  
  //第一次新增節點的時候要移動未指標,還要設定first的before
  if(list->first == list->first->next){
    list->last = p;
    p->next = list->first;
    list->first->before = p;
  }
  //不是第一次新增節點的時候,要把原第一個節點的before指向,新新增的節點
  else{
    p->next = list->first->next;
    list->first->next->before = p;
  }
  //設定頭指標的next節點
  list->first->next = p;
  
  list->size++;
}

void show_list(NodeList* list){
  Node* tmp = list->first->next;
  while(tmp != list->first){
    printf("%d->", tmp->data);
    tmp = tmp->next;
  }
  printf("NULL
");
}

void pop_back(NodeList* list){
  if(list->size == 0)return;
  
  free(list->last);
  //讓尾指標的next指向NULL
  list->last->before->next = list->first;
  //讓first的before指向新的尾節點
  list->first->before = list->last->before;
  //讓尾指標指向原尾節點的前一個節點
  list->last = list->last->before;

  list->size--;
}
void pop_front(NodeList* list){
  if(list->size == 0)return;

  free(list->first->next);
  //就剩一個節點的時候,要移動尾指標。
  if(list->first->next == list->last){
    list->last = list->first;
    list->last->next = list->first;
    list->first->before = list->last;
    list->size--;
    return;
  }
  
  //頭指標的next指向第二個節點
  list->first->next = list->first->next->next;
  //第二個節點的before指向頭節點
  list->first->next->before = list->first;

  list->size--;
}
void insert_val(NodeList* list, ElemType val){
  Node* n = create_node(val);;
  
  Node* p = list->first;
  while(p->next != list->first && val > p->next->data){
    p = p->next;
  }
  //第一次加節點,或者,最後一個節點的值也沒有比給的值大的時候
  if(list->first == p->next){
    n->next = list->first;
    n->before = list->last;
    list->last->next = n;
    list->first->before = n;
    list->last = n;
    list->size++;
    return;
  }
  //新節點的next指向原節點的下一個節點
  n->next = p->next;
  //原節點的next指向新節點,注意這句的位置必須在上句的下面
  p->next = n;
  //新節點的下一個節點的before指向新節點
  n->next->before = n;
  //新節點的before指向原節點
  n->before = p;

  list->size++;
}
//尋找給定值的節點的位置
Node* find(NodeList* list, ElemType val){
  if(list->size == 0)return NULL;

  Node* p = list->first;
  while(p->next != list->first && p->next->data != val){
    p = p->next;
  }
  if(list->first == p->next){
    return NULL;
  }
  printf("%d is found
", p->next->data);
  return p->next;
}
void delete_val(NodeList* list, ElemType val){
  Node* p = find(list, val);
  if(NULL == p) return;

  //刪除的節點是尾節點的時候,要移動last
  if(p == list->last){
    list->last = p->before;
    p->before->next = list->first;
    list->first->before = p->before;
    list->size--;
    return;
  }

  p->before->next = p->next;
  p->next->before = p->before;

  free(p);

  list->size--;
}

void sort(NodeList* list){
  if(list->size == 1 || list->size == 0)return;

  //p為第一個節點
  Node* p = list->first->next;

  //t是空白list,往t里加節點
  Node* t = list->first;
  list->last = list->first;
  list->last->next = list->first;
  list->first->before = list->last;
  
  size_t sz = list->size;
  
  Node* tmp;  
  while(sz-- > 0){
    //p的next會被改變,所以提前儲存
    tmp = p->next;
    while(t->next != list->first && p->data > t->next->data){
      t = t->next;
    }
    //t為first,或者t為last,都是尾插
    if(t->next == list->first){
      t->next = p;
      p->next = list->first;
      p->before = t;
      list->first->before = p;
      list->last = p;
    }
    else{
      p->next = t->next;
      t->next->before = p;

      t->next = p;
      p->before = t;
    }

    p = tmp;
    t = list->first;
  }
}

void resver(NodeList* list){
  if(list->size == 1 || list->size == 0)return;

  //第一個節點
  Node* head = list->first->next;
  //第二個節點
  Node* second = head->next;
  //head就是last,所以要head->next = NULL;
  list->last = head;
  list->last->next = list->first;
  list->first->before = list->last;

  Node* tmp;
  while(second != list->first){
    //必須儲存second的next,因為下面的程式碼,會改變second的next
    tmp = second->next;

    //頭插
    second->next = list->first->next;
    list->first->next->before = second;
    list->first->next = second;
    second->before = list->first;
    
    second = tmp;
  }
}

void clear(NodeList* list){
  Node* p = list->first->next;
  while(p != list->last){
    p = p->next;
    free(p);    
  }
  list->last = list->first;
  list->last->next = list->first;
  list->first->before = list->last;
  list->size = 0;
}

void destroy(NodeList* list){
  clear(list);
  free(list->first);
}

whileshuangnodemain.c

#include "whileshuangnode.h"

int main(){
  NodeList list;
  init(&list);
  int select = 1;
  ElemType item;
  Node* node = NULL;
  while(select){
    printf("*****************************************
");
    printf("*** [1]   push_back   [2]  push_front ***
");
    printf("*** [3]   show_list   [4]  pop_back   ***
");
    printf("*** [5]   pop_front   [6]  insert_val ***
");
    printf("*** [7]   find        [8]  length     ***
");
    printf("*** [9]   delete_val  [10] sort       ***
");
    printf("*** [11]  sort        [12] resver     ***
");
    printf("*** [13]              [14] clear      ***
");
    printf("*** [0]   quit        [15*]destroy    ***
");
    printf("*****************************************
");
    printf("請選擇:>");
    scanf("%d", &select);
    if(0 == select)
      break;
    switch(select){
    case 1:
      printf("請輸入要插入的資料,以-1結束>
");
      while(scanf("%d",&item) && item != -1){
    push_back(&list, item);
      }
      show_list(&list);
      break;
    case 2:
      printf("請輸入要插入的資料,以-1結束>
");
      while(scanf("%d", &item) && item != -1){
    push_front(&list, item);
      }
      show_list(&list);
      break;
    case 3:
      show_list(&list);
      break;
    case 4:
      pop_back(&list);
      show_list(&list);
      break;
    case 5:
      pop_front(&list);
      show_list(&list);
      break;
    case 6:
      printf("請輸入要插入的資料>
");
      scanf("%d",&item);
      insert_val(&list, item);
      show_list(&list);
      break;
    case 7:
      printf("please enter what you shoule find out>
");
      scanf("%d",&item);
      node = find(&list, item);
      if(node == NULL){
    printf("can not find %d
", item);
      }
      break;
    case 8:
      printf("length is %ld
", list.size);
      break;
    case 9:
      printf("please enter what you want to delete>
");
      scanf("%d",&item);      
      delete_val(&list, item);
      show_list(&list);
      break;
    case 10:
      // sort(&list);
      //show_list(&list);
      break;
    case 11:
      sort(&list);
      show_list(&list);
      break;
    case 12:
      resver(&list);
      show_list(&list);
      break;
    case 13:
      resver(&list);
      show_list(&list);
      break;
    case 14:
      clear(&list);
      show_list(&list);
      break;
    case 15:
      destroy(&list);
      break;
    default:
      break;
    }
  }

  //destroy(&list);
}

相關文章