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);
}