在单向循环链表中,如果要在末尾插入一个节点,必须从head
一个节点一个节点往后查询,尽管新建节点是插入在末尾节点和起始节点之间。在节点数较多的情况下,这一过程是费时的。此外,在实际应用中,有时需要逆向访问表中元素,这对单向链表或单向循环链表结构来说显然是困难的。为解决这一问题,可将链表设计成双向链表或双向循环链表。
以带表头节点的双向循环链表为例:
可见,双向循环链表的每个节点包含三个域:element
、prev
、next
。其中element
域为元素域,prev
为指向前驱节点的指针,next
为指向后继节点的指针。
双向循环链表的每个节点的结构都具有如下定义的结构类型(element
域定义为int
型数据):
struct _node
{
int element;
struct _node* prev;
struct _node* next;
};
typedef struct _node node;
双向循环链表的插入分末尾插入和数据有序插入来讨论。
在双向循环链表中,末尾插入不再需要从head
开始一个节点一个节点往后查询,在表头节点中存有指向末尾节点的指针,可以直接将新建节点插在末尾节点和表头节点。
bool NodeInsertLast(node* head, node* n)
{
ASSERT(head);
ASSERT(n);
head->element++;
node* ptr = head->prev;
n->next = ptr->next;
ptr->next->prev = n;
ptr->next = n;
n->prev = ptr;
return true;
}
bool NodeInsertOrder(node* head, node* n)
{
ASSERT(head);
ASSERT(n);
head->element++;
node* ptr = head->next;
while (ptr != head)
{
if (ptr->element > n->element)
break;
ptr = ptr->next;
}
ptr->prev->next = n;
n->prev = ptr->prev;
n->next = ptr;
ptr->prev = n;
return true;
}
可以看出,双向循环链表采用常规的有序插入办法,和单向循环链表的操作差别不大,主要是多了一个指针需要处理。
节点的删除,可以像单向循环链表那样,根据element
进行查找,然后删除;在实际项目中,节点在插入链表之后,指向该节点的指针变量一般并不会改变,所以对该节点中存放的数据进行修改,或是删除该节点时,也可以直接通过该指针变量进行操作。
element
进行删除bool NodeDeleteForEle(node* head, int element)
{
ASSERT(head);
head->element--;
node* ptr = head->next;
while (ptr != head)
{
if (ptr->element == element)
{
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
free(ptr);
return true;
}
ptr = ptr->next;
}
return false;
}
bool NodeDeleteForPtr(node* head, node* n)
{
ASSERT(head);
ASSERT(n);
head->element--;
n->prev->next = n->next;
n->next->prev = n->prev;
free(n);
return true;
}
void ListClear(node* head)
{
ASSERT(head);
head->element = 0;
node* ptr = head->next;
node* freePtr = NULL;
while (ptr != head)
{
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
freePtr = ptr;
ptr = ptr->next;
free(freePtr);
}
}
双向循环链表操作显示
#include
#include
#include
#define ASSERT(x) \
do \
{ \
if (!x) \
{ \
printf("%s assert false! function:%s, line:%d\r\n", #x, __FUNCTION__, __LINE__); \
while (1); \
} \
} while (0);
struct _node
{
int element;
struct _node* prev;
struct _node* next;
};
typedef struct _node node;
node* NodeCreate(int element)
{
node* ptr = (node*)malloc(sizeof(struct _node));
if (ptr == NULL)
{
return NULL;
}
ptr->element = element;
ptr->next = ptr;
ptr->prev = ptr;
return ptr;
}
bool NodeInsertLast(node* head, node* n)
{
ASSERT(head);
ASSERT(n);
head->element++;
node* ptr = head->prev;
n->next = ptr->next;
ptr->next->prev = n;
ptr->next = n;
n->prev = ptr;
return true;
}
bool NodeInsertOrder(node* head, node* n)
{
ASSERT(head);
ASSERT(n);
head->element++;
node* ptr = head->next;
while (ptr != head)
{
if (ptr->element > n->element)
break;
ptr = ptr->next;
}
ptr->prev->next = n;
n->prev = ptr->prev;
n->next = ptr;
ptr->prev = n;
return true;
}
bool NodeDeleteForEle(node* head, int element)
{
ASSERT(head);
head->element--;
node* ptr = head->next;
while (ptr != head)
{
if (ptr->element == element)
{
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
free(ptr);
return true;
}
ptr = ptr->next;
}
return false;
}
bool NodeDeleteForPtr(node* head, node* n)
{
ASSERT(head);
ASSERT(n);
head->element--;
n->prev->next = n->next;
n->next->prev = n->prev;
free(n);
return true;
}
void ListClear(node* head)
{
ASSERT(head);
head->element = 0;
node* ptr = head->next;
node* freePtr = NULL;
while (ptr != head)
{
ptr->prev->next = ptr->next;
ptr->next->prev = ptr->prev;
freePtr = ptr;
ptr = ptr->next;
free(freePtr);
}
}
/***************************************************************************/
#define LISTY 0
#define NODEY 10
#define COMMY 20
#define NODEW 18
#define LOCX(i) ((i)*NODEW-6)
node* nodeCreatePtr = NULL;
char* function[] =
{
"NodeCreate",
"NodeInsertLast",
"NodeInsertOrder",
"NodeDeleteForEle",
"NodeDeleteForPtr",
"ListClear"
};
void SetCursorPosition(int x, int y)
{
COORD cursorPisition;
cursorPisition.X = x;
cursorPisition.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursorPisition);
}
void ListPrintAtConsole(node* head)
{
node* ptr = head;
int nodeNum = 0;
/********************************新建节点********************************/
if (nodeCreatePtr != NULL)
{
SetCursorPosition(1, NODEY);
printf("新建节点");
SetCursorPosition(0, NODEY + 1);
printf("----------");
SetCursorPosition(0, NODEY + 2);
printf("----------");
SetCursorPosition(0, NODEY + 3);
printf("|%08d|", nodeCreatePtr->element);
SetCursorPosition(0, NODEY + 4);
printf("----------");
SetCursorPosition(0, NODEY + 5);
printf("|%8d|", nodeCreatePtr);
SetCursorPosition(0, NODEY + 6);
printf("----------");
SetCursorPosition(0, NODEY + 7);
printf("|%8d|", nodeCreatePtr);
}
/********************************头 指 针********************************/
SetCursorPosition(1, LISTY + 1);
printf("Head");
SetCursorPosition(0, LISTY + 2);
printf("----------");
SetCursorPosition(0, LISTY + 3);
printf("|%8d|------->", head);
SetCursorPosition(0, LISTY + 4);
printf("----------");
/********************************起始节点********************************/
ptr = head;
{
SetCursorPosition(LOCX(++nodeNum), LISTY);
printf(" --------------");
SetCursorPosition(LOCX(nodeNum), LISTY + 1);
printf(" | %8d", ptr);
SetCursorPosition(LOCX(nodeNum), LISTY + 2);
printf(" | ----------");
SetCursorPosition(LOCX(nodeNum), LISTY + 3);
printf("---|->|%8d|<-", ptr->element);
SetCursorPosition(LOCX(nodeNum), LISTY + 4);
printf("| | ----------");
SetCursorPosition(LOCX(nodeNum), LISTY + 5);
printf("| --|%8d|", ptr->prev);
SetCursorPosition(LOCX(nodeNum), LISTY + 6);
printf("| ----------");
SetCursorPosition(LOCX(nodeNum), LISTY + 7);
printf("| |%8d|--", ptr->next);
SetCursorPosition(LOCX(nodeNum), LISTY + 8);
printf("| ----------");
SetCursorPosition(LOCX(nodeNum), LISTY + 9);
printf(" ----------------- ");
}
/********************************中间节点********************************/
ptr = ptr->next;
while (ptr != head)
{
nodeNum++;
SetCursorPosition(LOCX(nodeNum), LISTY);
printf("------------------");
SetCursorPosition(LOCX(nodeNum), LISTY + 1);
printf(" %8d", ptr);
SetCursorPosition(LOCX(nodeNum), LISTY + 2);
printf(" ----------");
SetCursorPosition(LOCX(nodeNum), LISTY + 3);
printf(" ->|%8d|<-", ptr->element);
SetCursorPosition(LOCX(nodeNum), LISTY + 4);
printf("| | ----------");
SetCursorPosition(LOCX(nodeNum), LISTY + 5);
printf(" --|--|%8d|", ptr->prev);
SetCursorPosition(LOCX(nodeNum), LISTY + 6);
printf(" | ----------");
SetCursorPosition(LOCX(nodeNum), LISTY + 7);
printf("--- |%8d|--", ptr->next);
SetCursorPosition(LOCX(nodeNum), LISTY + 8);
printf(" ----------");
SetCursorPosition(LOCX(nodeNum), LISTY + 9);
printf("-------------------");
ptr = ptr->next;
}
SetCursorPosition(LOCX(nodeNum) + 18, LISTY + 1);
printf("|");
SetCursorPosition(LOCX(nodeNum) + 18, LISTY + 2);
printf("|");
SetCursorPosition(LOCX(nodeNum) + 18, LISTY + 8);
printf("|");
}
char GetCommand(void)
{
char command;
SetCursorPosition(0, COMMY);
printf("\r\n[T]:%s", function[0]);
printf("\r\n[L]:%s", function[1]);
printf("\r\n[O]:%s", function[2]);
printf("\r\n[E]:%s", function[3]);
printf("\r\n[P]:%s", function[4]);
printf("\r\n[C]:%s", function[5]);
printf("\r\n[Q]:Quit");
printf("\r\n请选择要操作的命令并按回车: ");
printf("\b");
while (true)
{
while ((command = getchar()) == '\n');
command = tolower(command);
if (command == 't' || command == 'l' || command == 'o' || command == 'e' || command == 'p' || command == 'c' || command == 'q')
{
while (getchar() != '\n');
return command;
}
printf("\r\n请输入有效命令或按获取帮助:");
}
}
void DoCommand(char Command, node* head)
{
int element = '\n';
switch (Command)
{
case 't':
{
printf("请输入创建节点的element值并按回车: ");
while (element == '\n')
scanf_s("%d", &element);
nodeCreatePtr = NodeCreate(element);
break;
}
case 'l':
{
if (nodeCreatePtr != NULL)
{
NodeInsertLast(head, nodeCreatePtr);
}
nodeCreatePtr = NULL;
break;
}
case 'o':
{
if (nodeCreatePtr != NULL)
{
NodeInsertOrder(head, nodeCreatePtr);
}
nodeCreatePtr = NULL;
break;
}
case 'e':
{
printf("请输入删除节点的element值并按回车: ");
while (element == '\n')
scanf_s("%d", &element);
NodeDeleteForEle(head, element);
break;
}
case 'p':
{
printf("请输入删除节点的地址并按回车: ");
while (element == '\n')
scanf_s("%d", &element);
NodeDeleteForPtr(head,(node*)element);
break;
}
case 'c':
{
ListClear(head);
break;
}
case 'q':
{
exit(0);
break;
}
}
}
int main()
{
node head = { 0, &head, &head };
while (1)
{
system("cls");
ListPrintAtConsole(&head);
DoCommand(GetCommand(), &head);
}
}