第十周知识总结

1.完成了循环双向链结表以及打印出反转循环双向链结表

部分代码

// 初始化双向链结表 L。
void initial(DList *L) {
L->head = NULL; // 将双向链结表的头节点指针设为空值。
L->tail = NULL; // 将双向链结表的尾节点指针设为空值。
}

// 取得双向链结表 L 的元素个数。
int getSize(DList L) {
Link current = L.head; // 节点指针。
int size = 0; // 线性表个数初始值设为 0.

if (current==NULL) return size; // 如果线性表为空,则元素个数为 0.

do { // 加一个节点计数。
size++; // 个数加 1。
current = current->next; // 下一个节点。
} while (current!=L.head); // 如果不是尾节点,继续搜寻。
return size; // 线性表 L 的元素个数。
}

// 取出循环双向链结表的第 i 个元素, 返回该元素的值。
// 若 inx<0, 向左移动;若 inx>0, 向右移动。
// 若 |inx| 大于双向链结表的元素个数,则循环重复计数。
ElemType getElem(DList L, int inx) {
Link current = L.head; // 头节点指针。
int i; // 循环变量。

if (current==NULL) return -1; // 如果线性表为空,则无此元素。

// 循环线性表,如果 inx>size, 会重复 L 的头节点。
for (i=0; i<abs(inx); i++)
if (inx>0) current = current->next; // 往右移到下一个元素。
else current = current->prev; // 往左移到前一个元素。
return current->elem; // 返回节点的元素值。
}

// 搜寻循环双向链结表的元素。若成功,返回元素位置;否则,返回 -1。
int search(DList L, ElemType e) {
Link current = L.head; // 头节点指针。
int position=0; // 元素位置,设定初始值为 0。

if (current==NULL) return -1; // 如果循环双向链结表为空,则无此元素。

do { // 循环双向链结表不是空的,至少做一次。
if (current->elem==e) return position; // 搜寻成功,返回元素 e 的位置。
else if (current->elem<e) { // 还有其它节点,继续搜寻。
position++; // 位置加 1。
current = current->next; // 移到下一个节点。
}
else return -1; // 节点的值已超过,搜寻失败。
} while (current!=L.head); // 若回到头节点,则停止循环。
return -1; // 已经超过循环双向链结表的最后一个节点,搜寻失败。
}

// 将一个元素插入到循环双向链结表,返回该元素的位置。
int insert(DList *L, ElemType e) {
Link current = L->head; // 指向头节点。
Link previous = L->tail; // 指向尾节点。
Link newNode; // 新节点的指针。
int size = getSize(*L); // 循环双向链结表的元素个数。
int position=0; // 目前节点位置。
if (current==NULL) { // Case 1:当循环双向链结表为空时。
newNode = (Link) malloc(sizeof(Node)); // 要求一个新节点的内存。
newNode->elem = e; // 复制节点的数据。
newNode->prev = newNode; // 循环双向链结表只有一个节点,prev 指向自己。
newNode->next = newNode; // 循环双向链结表只有一个节点,next 指向自己。
L->head = newNode; // 设定循环双向链结表只头节点。
L->tail = newNode; // 设定循环双向链结表只尾节点。
return position; // 头节点的位置为 0。
}

for (position=0; position<size; position++) { // 寻找插入位置。
if (current->elem>=e) break; // 找到第一个元素大于或等于 e 的节点。
previous = current; // 下一个 previous。
current = current->next; // 下一个 current。
}
if (position==0) { // Cases 2: 插入头节点的 current 之前。
newNode = (Link) malloc(sizeof(Node)); // 要求一个新节点的内存。
newNode->elem = e; // 复制目前节点的数据。
newNode->prev = previous; // 设定新节点的 prev 指针。
previous->next = newNode; // 将前一节点的 next 指针指向新节点。
newNode->next = current; // 设定新节点的 next 指针。
current->prev = newNode; // 将现节点的 prev 指针指向新节点。
L->head = newNode; // 更新头节点。
return position; // 返回位置。
}
else if (position<size) { // Cases 3: 插入中间节点的 current 之前。
newNode = (Link) malloc(sizeof(Node)); // 要求一个新节点的内存。
newNode->elem = e; // 复制目前节点的数据。
newNode->prev = previous; // 设定新节点的 prev 指针。
previous->next = newNode; // 将前一节点的 next 指针指向新节点。
newNode->next = current; // 设定新节点的 next 指针。
current->prev = newNode; // 将现节点的 prev 指针指向新节点。
return position; // 返回位置。
}

// Case 4:插入到循环双向链结表的尾节点之后,成为新的尾节点。
newNode = (Link) malloc(sizeof(Node)); // 要求一个新节点的内存。
newNode->elem = e; // 复制目前节点的数据。
newNode->prev = previous; // 设定新节点的 prev 指针。
previous->next = newNode; // 将前一节点的 next 指针指向新节点。
newNode->next = current; // 设定新节点的 next 指针。
current->prev = newNode; // 将现节点的 prev 指针指向新节点。
L->tail = newNode; // 插入的节点成为新的尾节点。
return position; // 返回位置。
}

// 从循环双向链结表删除一个元素。若成功,返回该元素原来的位置;
// 否则,返回 -1。
int delete(DList *L, ElemType e) {
Link current = L->head; // 指向头节点。
Link previous = L->tail; // 指向尾节点。
int position = 0; // 目前节点位置。

if (current==NULL) return -1; // 若循环双向链结表为空,删除失败。

do { // 当循环双向链结表还有节点。
if (current->elem==e) { // 找到要删除的节点。
if (position==0) { // 删除的节点是头节点。
if (current->next==current) { // 循环双向链结表只有一个节点。
L->head = NULL; // 将头节点清空。
L->tail = NULL; // 将尾节点清空。
}
else {
previous->next = current->next; // 修改前一个节点的 next 指针。
current->next->prev = previous; // 修改下一个节点的 prev 指针。
L->head = current->next; // 更新头节点。
}
free(current); // 释放删除的节点。
return position; // 返回删除节点的原来位置。
}
else {
if (current->next==L->head) // 删除的是尾节点。
L->tail = previous; // 更新尾节点。
previous->next = current->next; // 修改前一个节点的 next 指针。
current->next->prev = previous; // 修改下一个节点的 prev 指针。
free(current); // 释放删除的节点。
return position; // 返回删除节点的原来位置。
}
}
else if (current->elem<e) { // 检查下一个节点。
previous = current; // 将目前的节点设为前一个节点。
current = current->next; // 将下一个节点设为下一步骤的目前节点。
position++; // 位置加 1。
}
else return -1; // 目前节点数据已超过删除的值;删除失败。
} while (current!=L->head); // 若还没回到头节点,继续检查。

return -1; // current 回到头节点,删除失败。
}

// 将循环双向链结表清空。
void clear(DList *L) {
Link current = L->head; // 指向目前的节点。
Link previous; // 前一个节点。

while (current->next!=L->head) { // 不是尾节点。
previous = current; // 目前的节点。
current = current->next; // 下一个节点。
free(previous); // 释放目前的节点。
}
free(current); // 释放尾节点。
L->head = NULL; // 将循环双向链结表的头节点设为空。
L->tail = NULL; // 将循环双向链结表设尾节点设为空。
}

// 檢查循环双向链结表是否為空表。若是空,返回 1;否则,返回 0。
int is_empty(DList L) {
return L.head==NULL; // 若 L 的头节点为空,返回 1,否则,返回 0。
}
// 打印循环双向链结表元素。
void printlst(DList L) {
Link current = L.head; // 指向目前的节点。
int position = 0; // 目前节点的位置。

printf("线性表元素个数:%3d 元素 ", getSize(L));

if (current!=NULL) { // 循环双向链结表不是空的,开始打印。
while (current->next!=L.head) { // 还有节点要打印。
printf("%3d ", current->elem); // 打印节点数据。
if ((position+1)%20==0) printf(" "); // 满 20 个元素,打印换行。
current = current->next; // 移到下一个节点。
position++; // 下一个位置。
}
printf("%3d ", current->elem); // 打印尾节点数据和换行。
}
printf(" "); // 打印一个换行。
}

 2.关于循环双向链结表的思维导图

删除思维导图如下

原文地址:https://www.cnblogs.com/mju3197103150/p/12864150.html