"双向循环链表"是一个很方便的复合型数据结构,这种结构既能向前找结点,又能向后找结点!利用这个特性,就能够很便捷地实现 “栈” 和 “队列”
- (创建链表时,采用头插法) 从尾向头,遍历链表 —— 队列
- (创建链表时,采用头插法) 从头往尾,遍历链表 —— 栈
- (创建链表时,采用尾插法) 从尾向头,遍历链表 —— 栈
- (创建链表时,采用尾插法) 从头往尾,遍历链表 —— 队列
注意:不能混着用。如果有时用头插,有时用尾插,那就没法很便捷地实现 “队列” 和 “栈” 了!
一举多得:双向循环链表会写了,单向链表、单向循环链表、双向链表也就会写啦!!!嘿嘿嘿
这种 “循环数据结构” 可以很方便地进行动态调整,如果要使用数组实现队列(不循环的),那么实现过程中,需要把数据进行不断地移位,以对齐到起始(或者最后)的位置!这就比较麻烦了!
“循环”的意义在于:“头”可以是这个循环中的任意一个位置!从而避免了 “对齐” 这种大规模移动数据操作!
1 原子数据抽象
typedef struct _tag_Node{
int num;
struct _tag_Node *pNext;
struct _tag_Node *pPrev;
}node;
2 创建链表
2.1 带头结点的
2.1.1 创建头结点
node *createListWithHead(void){
// Pointer variable: linking the pointer to an entity
node *phead = (node *)malloc(sizeof(node));
if(phead == NULL){
// Defensive programming
return NULL;
}
// Initializing the variable; Differentiation.
phead->pNext = phead;
phead->pPrev = phead;
return phead;
}
2.1.2 使用数组创建带头结点链表
node *createListWithHead_UsingArray(int *arr, int len){
node* list = createListWithHead();
if(list == NULL){
// Defensive programming
return NULL;
}
node *p = list; // Defining an auxiliary pointer.
for(int i = 0; i < len; i++){
node *newNode = (node *)malloc(sizeof(node));
if(newNode == NULL){
// Defensive programming
return list;
}
newNode->num = arr[i]; // Loading data to the new node.
// Inserting a new node at the tail.
newNode->pPrev = p;
newNode->pNext = list;
p->pNext = newNode;
list->pPrev = newNode