线性表代码基本例题及详细解释(2)

1.编写算法,在单链表中查找第一个值为x的结点,并输出其前驱和后继的存储位置。

#include <stdio.h>
#include <stdlib.h>

// 链表节点定义
typedef struct Node {
int data;
struct Node *next;
} Node;

// 链表定义
typedef struct {
Node *head;
} LinkedList;

// 初始化链表
void initLinkedList(LinkedList *list) {
list->head = NULL;
}

// 在链表尾部插入节点
void insertAtTail(LinkedList *list, int value) {
Node *newNode = (Node *)malloc(sizeof(Node));
if (!newNode) {
printf("Memory error\n");
return;
}
newNode->data = value;
newNode->next = NULL;

if (list->head == NULL) {
list->head = newNode;
} else {
Node *temp = list->head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
}

// 查找值为 x 的节点并输出其前驱和后继的存储位置
void findNodeAndPrintPredecessorSuccessor(LinkedList *list, int x) {
if (list->head == NULL) {
printf("The linked list is empty.\n");
return;
}

Node *prev = NULL;
Node *current = list->head;
Node *next = current->next;

while (current != NULL) {
if (current->data == x) {
printf("Node with value %d found.\n", x);
if (prev != NULL) {
printf("Predecessor address: %p\n", (void *)prev);
} else {
printf("No predecessor (it's the head node).\n");
}
if (next != NULL) {
printf("Successor address: %p\n", (void *)next);
} else {
printf("No successor (it's the last node).\n");
}
return;
}
prev = current;
current = next;
if (next != NULL) {
next = next->next;
}
}

printf("Node with value %d not found.\n", x);
}

// 打印链表的内容
void printLinkedList(const LinkedList *list) {
Node *temp = list->head;
while (temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}

int main() {
LinkedList list;
initLinkedList(&list);

// 用户输入链表中的元素
int n;
printf("Enter the number of elements in the linked list: ");
scanf("%d", &n);

printf("Enter the elements of the linked list:\n");
for (int i = 0; i < n; i++) {
int value;
scanf("%d", &value);
insertAtTail(&list, value);
}

printf("Original linked list: ");
printLinkedList(&list);

int x;
printf("Enter the value to search for: ");
scanf("%d", &x);

findNodeAndPrintPredecessorSuccessor(&list, x);

// 清理内存
Node *current = list.head;
while (current != NULL) {
Node *temp = current;
current = current->next;
free(temp);
}

return 0;
}
      

数据结构定义

// 链表节点定义
typedef struct Node {
    int data;
    struct Node *next;
} Node;

// 链表定义
typedef struct {
    Node *head;
} LinkedList;
  • Node 结构体定义了一个链表节点,包含两个成员:
    • int data:存储节点的数据。
    • struct Node *next:指向下一个节点的指针。
  • LinkedList 结构体定义了一个链表,包含一个成员:
    • Node *head:指向链表头节点的指针。

初始化链表

// 初始化链表
void initLinkedList(LinkedList *list) {
    list->head = NULL;
}
  • 将链表的头节点初始化为 NULL,表示链表为空。

在链表尾部插入节点

// 在链表尾部插入节点
void insertAtTail(LinkedList *list, int value) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (!newNode) {
        printf("Memory error\n");
        return;
    }
    newNode->data = value;
    newNode->next = NULL;

    if (list->head == NULL) {
        list->head = newNode;
    } else {
        Node *temp = list->head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
}
  • 创建一个新的节点 newNode,并分配内存。
  • 将新节点的数据设置为 value,并将 next 指针设置为 NULL
  • 如果链表为空(即 head 为 NULL),将新节点设置为头节点。
  • 否则,遍历链表找到最后一个节点,并将新节点链接到最后一个节点的 next 指针上。

查找值为 x 的节点并输出其前驱和后继的存储位置

​
// 在链表尾部插入节点
void insertAtTail(LinkedList *list, int value) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (!newNode) {
        printf("Memory error\n");
        return;
    }
    newNode->data = value;
    newNode->next = NULL;

    if (list->head == NULL) {
        list->head = newNode;
    } else {
        Node *temp = list->head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
}

​
  • 检查链表是否为空,如果是,则输出提示信息并返回。
  • 初始化三个指针:
    • prev:前一个节点,初始为 NULL
    • current:当前节点,初始为头节点。
    • next:下一个节点,初始为头节点的下一个节点。
  • 使用 while 循环遍历链表:
    • 如果当前节点的数据等于 x,输出当前节点的信息:
      • 输出当前节点的值。
      • 如果有前一个节点,输出前一个节点的地址;否则输出没有前驱。
      • 如果有下一个节点,输出下一个节点的地址;否则输出没有后继。
    • 移动 prev 和 current 指针。
    • 如果 next 不为 NULL,移动 next 指针。
  • 如果遍历完整个链表都没有找到值为 x 的节点,输出提示信息。

打印链表的内容

// 打印链表的内容
void printLinkedList(const LinkedList *list) {
    Node *temp = list->head;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}
  • 遍历链表,逐个打印每个节点的数据。
  • 打印完所有节点后,输出一个换行符。

主函数

int main() {
    LinkedList list;
    initLinkedList(&list);

    // 用户输入链表中的元素
    int n;
    printf("Enter the number of elements in the linked list: ");
    scanf("%d", &n);

    printf("Enter the elements of the linked list:\n");
    for (int i = 0; i < n; i++) {
        int value;
        scanf("%d", &value);
        insertAtTail(&list, value);
    }

    printf("Original linked list: ");
    printLinkedList(&list);

    int x;
    printf("Enter the value to search for: ");
    scanf("%d", &x);

    findNodeAndPrintPredecessorSuccessor(&list, x);

    // 清理内存
    Node *current = list.head;
    while (current != NULL) {
        Node *temp = current;
        current = current->next;
        free(temp);
    }

    return 0;
}
  • 初始化一个链表 list
  • 提示用户输入链表中元素的数量 n
  • 提示用户输入链表中的每个元素,并调用 insertAtTail 函数将其插入到链表中。
  • 打印原始链表的内容。
  • 提示用户输入要查找的值 x,并调用 findNodeAndPrintPredecessorSuccessor 函数查找值为 x 的节点并输出其前驱和后继的存储位置。
  • 清理链表中所有节点的内存,防止内存泄漏。
  • 返回0,表示程序正常结束。

示例运行

假设用户输入以下数据:

Enter the number of elements in the linked list: 5
Enter the elements of the linked list:
3 1 4 1 5
Original linked list: 3 -> 1 -> 4 -> 1 -> 5 -> NULL
Enter the value to search for: 4
Node with value 4 found.
Predecessor address: 0x5555555592b0
Successor address: 0x5555555592d0

在这个示例中:

  • 用户输入了5个元素 [3, 1, 4, 1, 5]
  • 原始链表为 3 -> 1 -> 4 -> 1 -> 5 -> NULL
  • 用户输入要查找的值 4,程序找到值为 4 的节点,并输出其前驱和后继的存储地址。

2.在单循环链表中,编写算法实现将链表中数据域为奇数的结点移至表头,将链表中数据域为偶数的结点移至表尾。

#include <stdio.h>
#include <stdlib.h>

// 链表节点定义
typedef struct Node {
int data;
struct Node *next;
} Node;

// 链表定义
typedef struct {
Node *head;
} LinkedList;

// 初始化链表
void initLinkedList(LinkedList *list) {
list->head = NULL;
}

// 在链表尾部插入节点
void insertAtTail(LinkedList *list, int value) {
Node *newNode = (Node *)malloc(sizeof(Node));
if (!newNode) {
printf("Memory error\n");
return;
}
newNode->data = value;

if (list->head == NULL) {
list->head = newNode;
newNode->next = newNode; // 循环链表特性
} else {
Node *temp = list->head;
while (temp->next != list->head) {
temp = temp->next;
}
temp->next = newNode;
newNode->next = list->head; // 循环链表特性
}
}

// 调整链表顺序,将奇数节点移至表头,偶数节点移至表尾
void rearrangeLinkedList(LinkedList *list) {
if (list->head == NULL || list->head->next == list->head) {
return; // 如果链表为空或只有一个元素,则无需处理
}

Node *oddHead = NULL;
Node *oddTail = NULL;
Node *evenHead = NULL;
Node *evenTail = NULL;

Node *current = list->head;
Node *start = list->head;

do {
if (current->data % 2 == 0) { // 偶数节点
if (evenHead == NULL) {
evenHead = current;
evenTail = current;
} else {
evenTail->next = current;
evenTail = current;
}
} else { // 奇数节点
if (oddHead == NULL) {
oddHead = current;
oddTail = current;
} else {
oddTail->next = current;
oddTail = current;
}
}
current = current->next;
} while (current != start);

// 连接奇数部分和偶数部分
if (oddHead != NULL) {
oddTail->next = evenHead;
list->head = oddHead;
} else {
list->head = evenHead;
}

if (evenTail != NULL) {
evenTail->next = list->head; // 循环链表特性
}
}

// 打印链表的内容
void printLinkedList(const LinkedList *list) {
if (list->head == NULL) {
printf("NULL\n");
return;
}

Node *temp = list->head;
do {
printf("%d -> ", temp->data);
temp = temp->next;
} while (temp != list->head);
printf("HEAD\n");
}

int main() {
LinkedList list;
initLinkedList(&list);

// 用户输入链表中的元素
int n;
printf("Enter the number of elements in the circular linked list: ");
scanf("%d", &n);

printf("Enter the elements of the circular linked list:\n");
for (int i = 0; i < n; i++) {
int value;
scanf("%d", &value);
insertAtTail(&list, value);
}

printf("Original circular linked list: ");
printLinkedList(&list);

rearrangeLinkedList(&list);

printf("Rearranged circular linked list: ");
printLinkedList(&list);

// 清理内存
if (list.head != NULL) {
Node *current = list.head;
Node *start = list.head;
do {
Node *temp = current;
current = current->next;
free(temp);
} while (current != start);
}

return 0;
}

数据结构定义

// 链表节点定义
typedef struct Node {
    int data;
    struct Node *next;
} Node;

// 链表定义
typedef struct {
    Node *head;
} LinkedList;
  • Node 结构体定义了一个链表节点,包含两个成员:
    • int data:存储节点的数据。
    • struct Node *next:指向下一个节点的指针。
  • LinkedList 结构体定义了一个链表,包含一个成员:
    • Node *head:指向链表头节点的指针。

初始化链表

// 初始化链表
void initLinkedList(LinkedList *list) {
    list->head = NULL;
}
  • 将链表的头节点初始化为 NULL,表示链表为空。

在链表尾部插入节点

// 在链表尾部插入节点
void insertAtTail(LinkedList *list, int value) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (!newNode) {
        printf("Memory error\n");
        return;
    }
    newNode->data = value;

    if (list->head == NULL) {
        list->head = newNode;
        newNode->next = newNode; // 循环链表特性
    } else {
        Node *temp = list->head;
        while (temp->next != list->head) {
            temp = temp->next;
        }
        temp->next = newNode;
        newNode->next = list->head; // 循环链表特性
    }
}
  • 创建一个新的节点 newNode,并分配内存。
  • 将新节点的数据设置为 value
  • 如果链表为空(即 head 为 NULL),将新节点设置为头节点,并将 next 指针指向自身,形成一个单节点的循环链表。
  • 否则,遍历链表找到最后一个节点,并将新节点链接到最后一个节点的 next 指针上,同时将新节点的 next 指针指向头节点,保持循环特性。

调整链表顺序,将奇数节点移至表头,偶数节点移至表尾

// 调整链表顺序,将奇数节点移至表头,偶数节点移至表尾
void rearrangeLinkedList(LinkedList *list) {
    if (list->head == NULL || list->head->next == list->head) {
        return; // 如果链表为空或只有一个元素,则无需处理
    }

    Node *oddHead = NULL;
    Node *oddTail = NULL;
    Node *evenHead = NULL;
    Node *evenTail = NULL;

    Node *current = list->head;
    Node *start = list->head;

    do {
        if (current->data % 2 == 0) { // 偶数节点
            if (evenHead == NULL) {
                evenHead = current;
                evenTail = current;
            } else {
                evenTail->next = current;
                evenTail = current;
            }
        } else { // 奇数节点
            if (oddHead == NULL) {
                oddHead = current;
                oddTail = current;
            } else {
                oddTail->next = current;
                oddTail = current;
            }
        }
        current = current->next;
    } while (current != start);

    // 连接奇数部分和偶数部分
    if (oddHead != NULL) {
        oddTail->next = evenHead;
        list->head = oddHead;
    } else {
        list->head = evenHead;
    }

    if (evenTail != NULL) {
        evenTail->next = list->head; // 循环链表特性
    }
}
  • 检查链表是否为空或只有一个节点,如果是,则直接返回。
  • 初始化四个指针:
    • oddHead 和 oddTail:分别指向奇数节点的头部和尾部。
    • evenHead 和 evenTail:分别指向偶数节点的头部和尾部。
  • 使用 do-while 循环遍历链表:
    • 如果当前节点的数据是偶数,将其链接到偶数部分。
    • 如果当前节点的数据是奇数,将其链接到奇数部分。
  • 循环结束后,连接奇数部分和偶数部分:
    • 如果有奇数部分,将奇数部分的尾部链接到偶数部分的头部,并将链表的头节点设置为奇数部分的头部。
    • 如果没有奇数部分,将链表的头节点设置为偶数部分的头部。
  • 如果有偶数部分,将偶数部分的尾部链接到链表的头节点,保持循环特性。

打印链表的内容

// 打印链表的内容
void printLinkedList(const LinkedList *list) {
    if (list->head == NULL) {
        printf("NULL\n");
        return;
    }

    Node *temp = list->head;
    do {
        printf("%d -> ", temp->data);
        temp = temp->next;
    } while (temp != list->head);
    printf("HEAD\n");
}
  • 检查链表是否为空,如果是,则输出 NULL 并返回。
  • 使用 do-while 循环遍历链表,逐个打印每个节点的数据。
  • 循环结束后,输出一个换行符。

主函数

int main() {
    LinkedList list;
    initLinkedList(&list);

    // 用户输入链表中的元素
    int n;
    printf("Enter the number of elements in the circular linked list: ");
    scanf("%d", &n);

    printf("Enter the elements of the circular linked list:\n");
    for (int i = 0; i < n; i++) {
        int value;
        scanf("%d", &value);
        insertAtTail(&list, value);
    }

    printf("Original circular linked list: ");
    printLinkedList(&list);

    rearrangeLinkedList(&list);

    printf("Rearranged circular linked list: ");
    printLinkedList(&list);

    // 清理内存
    if (list.head != NULL) {
        Node *current = list.head;
        Node *start = list.head;
        do {
            Node *temp = current;
            current = current->next;
            free(temp);
        } while (current != start);
    }

    return 0;
}
  • 初始化一个链表 list
  • 提示用户输入链表中元素的数量 n
  • 提示用户输入链表中的每个元素,并调用 insertAtTail 函数将其插入到链表中。
  • 打印原始链表的内容。
  • 调用 rearrangeLinkedList 函数调整链表顺序,将奇数节点移至表头,偶数节点移至表尾。
  • 再次打印链表的内容,显示调整后的结果。
  • 清理链表中所有节点的内存,防止内存泄漏。
  • 返回0,表示程序正常结束。

示例运行

假设用户输入以下数据:

Enter the number of elements in the circular linked list: 5
Enter the elements of the circular linked list:
3 1 4 1 5
Original circular linked list: 3 -> 1 -> 4 -> 1 -> 5 -> HEAD
Rearranged circular linked list: 3 -> 1 -> 1 -> 5 -> 4 -> HEAD

在这个示例中:

  • 用户输入了5个元素 [3, 1, 4, 1, 5]
  • 原始循环链表为 3 -> 1 -> 4 -> 1 -> 5 -> HEAD
  • 调整链表顺序后,奇数节点 [3, 1, 1, 5] 被移至表头,偶数节点 [4] 被移至表尾,结果为 3 -> 1 -> 1 -> 5 -> 4 -> HEAD

3.将两个有序线性表 LIST 1=(a1,a2,...,an)和LIST 2=(b1,b2,...bm)链接成一个有序线性表LIST3 ,并删除 LIST 3中相同的结点,即 LIST3中若有多个结点具有相同的数据域,只保留一个结点,使得 LIST3中所有结点的数据域都不相同。在采用顺序表和单链表两种形式下分别设计C语言算法实现上述功能。

顺序表

#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 1000 // 最大容量

// 顺序表类型定义
typedef struct {
int data[MAX_SIZE]; // 存储数据的数组
int length; // 当前长度
} SeqList;

// 初始化顺序表
void initSeqList(SeqList *list) {
list->length = 0;
}

// 插入元素到顺序表
void insertElement(SeqList *list, int value) {
if (list->length >= MAX_SIZE) {
printf("Sequence list is full.\n");
return;
}
list->data[list->length++] = value;
}

// 合并两个有序顺序表并删除重复节点
void mergeSeqLists(SeqList *list1, SeqList *list2, SeqList *list3) {
int i = 0, j = 0, k = 0;

while (i < list1->length && j < list2->length) {
if (list1->data[i] < list2->data[j]) {
if (k == 0 || list1->data[i] != list3->data[k - 1]) {
list3->data[k++] = list1->data[i];
}
i++;
} else if (list1->data[i] > list2->data[j]) {
if (k == 0 || list2->data[j] != list3->data[k - 1]) {
list3->data[k++] = list2->data[j];
}
j++;
} else {
if (k == 0 || list1->data[i] != list3->data[k - 1]) {
list3->data[k++] = list1->data[i];
}
i++;
j++;
}
}

while (i < list1->length) {
if (k == 0 || list1->data[i] != list3->data[k - 1]) {
list3->data[k++] = list1->data[i];
}
i++;
}

while (j < list2->length) {
if (k == 0 || list2->data[j] != list3->data[k - 1]) {
list3->data[k++] = list2->data[j];
}
j++;
}

list3->length = k;
}

// 打印顺序表的内容
void printSeqList(const SeqList *list) {
for (int i = 0; i < list->length; i++) {
printf("%d ", list->data[i]);
}
printf("\n");
}

int main() {
SeqList list1, list2, list3;
initSeqList(&list1);
initSeqList(&list2);
initSeqList(&list3);

// 用户输入顺序表1中的元素
int n1;
printf("Enter the number of elements in LIST1: ");
scanf("%d", &n1);

printf("Enter the elements of LIST1:\n");
for (int i = 0; i < n1; i++) {
int value;
scanf("%d", &value);
insertElement(&list1, value);
}

// 用户输入顺序表2中的元素
int n2;
printf("Enter the number of elements in LIST2: ");
scanf("%d", &n2);

printf("Enter the elements of LIST2:\n");
for (int i = 0; i < n2; i++) {
int value;
scanf("%d", &value);
insertElement(&list2, value);
}

printf("LIST1: ");
printSeqList(&list1);

printf("LIST2: ");
printSeqList(&list2);

mergeSeqLists(&list1, &list2, &list3);

printf("Merged and deduplicated LIST3: ");
printSeqList(&list3);

return 0;

单链表

#include <stdio.h>
#include <stdlib.h>

// 链表节点定义
typedef struct Node {
int data;
struct Node *next;
} Node;

// 链表定义
typedef struct {
Node *head;
} LinkedList;

// 初始化链表
void initLinkedList(LinkedList *list) {
list->head = NULL;
}

// 在链表尾部插入节点
void insertAtTail(LinkedList *list, int value) {
Node *newNode = (Node *)malloc(sizeof(Node));
if (!newNode) {
printf("Memory error\n");
return;
}
newNode->data = value;
newNode->next = NULL;

if (list->head == NULL) {
list->head = newNode;
} else {
Node *temp = list->head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
}

// 合并两个有序单链表并删除重复节点
void mergeLinkedLists(LinkedList *list1, LinkedList *list2, LinkedList *list3) {
Node *p1 = list1->head;
Node *p2 = list2->head;
Node *tail = NULL;
Node *prev = NULL;

while (p1 != NULL && p2 != NULL) {
if (p1->data < p2->data) {
if (prev == NULL || p1->data != prev->data) {
if (tail == NULL) {
tail = p1;
list3->head = p1;
} else {
tail->next = p1;
tail = p1;
}
}
prev = p1;
p1 = p1->next;
} else if (p1->data > p2->data) {
if (prev == NULL || p2->data != prev->data) {
if (tail == NULL) {
tail = p2;
list3->head = p2;
} else {
tail->next = p2;
tail = p2;
}
}
prev = p2;
p2 = p2->next;
} else {
if (prev == NULL || p1->data != prev->data) {
if (tail == NULL) {
tail = p1;
list3->head = p1;
} else {
tail->next = p1;
tail = p1;
}
}
prev = p1;
p1 = p1->next;
p2 = p2->next;
}
}

while (p1 != NULL) {
if (prev == NULL || p1->data != prev->data) {
if (tail == NULL) {
tail = p1;
list3->head = p1;
} else {
tail->next = p1;
tail = p1;
}
}
prev = p1;
p1 = p1->next;
}

while (p2 != NULL) {
if (prev == NULL || p2->data != prev->data) {
if (tail == NULL) {
tail = p2;
list3->head = p2;
} else {
tail->next = p2;
tail = p2;
}
}
prev = p2;
p2 = p2->next;
}

if (tail != NULL) {
tail->next = NULL;
}
}

// 打印链表的内容
void printLinkedList(const LinkedList *list) {
Node *temp = list->head;
while (temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}

int main() {
LinkedList list1, list2, list3;
initLinkedList(&list1);
initLinkedList(&list2);
initLinkedList(&list3);

// 用户输入链表1中的元素
int n1;
printf("Enter the number of elements in LIST1: ");
scanf("%d", &n1);

printf("Enter the elements of LIST1:\n");
for (int i = 0; i < n1; i++) {
int value;
scanf("%d", &value);
insertAtTail(&list1, value);
}

// 用户输入链表2中的元素
int n2;
printf("Enter the number of elements in LIST2: ");
scanf("%d", &n2);

printf("Enter the elements of LIST2:\n");
for (int i = 0; i < n2; i++) {
int value;
scanf("%d", &value);
insertAtTail(&list2, value);
}

printf("LIST1: ");
printLinkedList(&list1);

printf("LIST2: ");
printLinkedList(&list2);

mergeLinkedLists(&list1, &list2, &list3);

printf("Merged and deduplicated LIST3: ");
printLinkedList(&list3);

// 清理内存
Node *current = list1.head;
while (current != NULL) {
Node *temp = current;
current = current->next;
free(temp);
}

current = list2.head;
while (current != NULL) {
Node *temp = current;
current = current->next;
free(temp);
}

current = list3.head;
while (current != NULL) {
Node *temp = current;
current = current->next;
free(temp);
}

return 0;
}

以顺序表为例详细分析:

数据结构定义

// 链表节点定义
typedef struct Node {
    int data;
    struct Node *next;
} Node;

// 链表定义
typedef struct {
    Node *head;
} LinkedList;
  • Node 结构体定义了一个链表节点,包含两个成员:
    • int data:存储节点的数据。
    • struct Node *next:指向下一个节点的指针。
  • LinkedList 结构体定义了一个链表,包含一个成员:
    • Node *head:指向链表头节点的指针。

初始化链表

// 初始化链表
void initLinkedList(LinkedList *list) {
    list->head = NULL;
}
  • 将链表的头节点初始化为 NULL,表示链表为空。

在链表尾部插入节点

 // 在链表尾部插入节点
void insertAtTail(LinkedList *list, int value) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (!newNode) {
        printf("Memory error\n");
        return;
    }
    newNode->data = value;
    newNode->next = NULL;

    if (list->head == NULL) {
        list->head = newNode;
    } else {
        Node *temp = list->head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = newNode;
    }
}
  • 创建一个新的节点 newNode,并分配内存。
  • 将新节点的数据设置为 value,并将 next 指针设置为 NULL
  • 如果链表为空(即 head 为 NULL),将新节点设置为头节点。
  • 否则,遍历链表找到最后一个节点,并将新节点链接到最后一个节点的 next 指针上。

合并两个有序单链表并删除重复节点

// 合并两个有序单链表并删除重复节点
void mergeLinkedLists(LinkedList *list1, LinkedList *list2, LinkedList *list3) {
    Node *p1 = list1->head;
    Node *p2 = list2->head;
    Node *tail = NULL;
    Node *prev = NULL;

    while (p1 != NULL && p2 != NULL) {
        if (p1->data < p2->data) {
            if (prev == NULL || p1->data != prev->data) {
                if (tail == NULL) {
                    tail = p1;
                    list3->head = p1;
                } else {
                    tail->next = p1;
                    tail = p1;
                }
            }
            prev = p1;
            p1 = p1->next;
        } else if (p1->data > p2->data) {
            if (prev == NULL || p2->data != prev->data) {
                if (tail == NULL) {
                    tail = p2;
                    list3->head = p2;
                } else {
                    tail->next = p2;
                    tail = p2;
                }
            }
            prev = p2;
            p2 = p2->next;
        } else {
            if (prev == NULL || p1->data != prev->data) {
                if (tail == NULL) {
                    tail = p1;
                    list3->head = p1;
                } else {
                    tail->next = p1;
                    tail = p1;
                }
            }
            prev = p1;
            p1 = p1->next;
            p2 = p2->next;
        }
    }

    while (p1 != NULL) {
        if (prev == NULL || p1->data != prev->data) {
            if (tail == NULL) {
                tail = p1;
                list3->head = p1;
            } else {
                tail->next = p1;
                tail = p1;
            }
        }
        prev = p1;
        p1 = p1->next;
    }

    while (p2 != NULL) {
        if (prev == NULL || p2->data != prev->data) {
            if (tail == NULL) {
                tail = p2;
                list3->head = p2;
            } else {
                tail->next = p2;
                tail = p2;
            }
        }
        prev = p2;
        p2 = p2->next;
    }

    if (tail != NULL) {
        tail->next = NULL;
    }
}
  • 初始化三个指针:
    • p1:指向链表1的头节点。
    • p2:指向链表2的头节点。
    • tail:指向合并后链表的尾节点。
    • prev:记录上一个插入的节点。
  • 使用 while 循环遍历链表1和链表2:
    • 如果 p1 的数据小于 p2 的数据,检查是否需要插入 p1 节点。
    • 如果 p1 的数据大于 p2 的数据,检查是否需要插入 p2 节点。
    • 如果 p1 和 p2 的数据相等,只插入其中一个节点,并移动两个指针。
  • 遍历完成后,处理剩余的节点:
    • 如果 p1 还有剩余节点,继续处理。
    • 如果 p2 还有剩余节点,继续处理。
  • 最后,确保合并后链表的尾节点的 next 指针为 NULL

打印链表的内容

// 打印链表的内容
void printLinkedList(const LinkedList *list) {
    Node *temp = list->head;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}
  • 从头节点开始遍历链表。
  • 逐个打印每个节点的数据。
  • 打印完所有节点后,输出一个换行符。

主函数

int main() {
    LinkedList list1, list2, list3;
    initLinkedList(&list1);
    initLinkedList(&list2);
    initLinkedList(&list3);

    // 用户输入链表1中的元素
    int n1;
    printf("Enter the number of elements in LIST1: ");
    scanf("%d", &n1);

    printf("Enter the elements of LIST1:\n");
    for (int i = 0; i < n1; i++) {
        int value;
        scanf("%d", &value);
        insertAtTail(&list1, value);
    }

    // 用户输入链表2中的元素
    int n2;
    printf("Enter the number of elements in LIST2: ");
    scanf("%d", &n2);

    printf("Enter the elements of LIST2:\n");
    for (int i = 0; i < n2; i++) {
        int value;
        scanf("%d", &value);
        insertAtTail(&list2, value);
    }

    printf("LIST1: ");
    printLinkedList(&list1);

    printf("LIST2: ");
    printLinkedList(&list2);

    mergeLinkedLists(&list1, &list2, &list3);

    printf("Merged and deduplicated LIST3: ");
    printLinkedList(&list3);

    // 清理内存
    Node *current = list1.head;
    while (current != NULL) {
        Node *temp = current;
        current = current->next;
        free(temp);
    }

    current = list2.head;
    while (current != NULL) {
        Node *temp = current;
        current = current->next;
        free(temp);
    }

    current = list3.head;
    while (current != NULL) {
        Node *temp = current;
        current = current->next;
        free(temp);
    }

    return 0;
}
  • 初始化三个链表 list1list2 和 list3
  • 提示用户输入链表1中的节点数量 n1
  • 提示用户输入链表1中的每个节点的数据,并调用 insertAtTail 函数将其插入到链表1中。
  • 提示用户输入链表2中的节点数量 n2
  • 提示用户输入链表2中的每个节点的数据,并调用 insertAtTail 函数将其插入到链表2中。
  • 打印链表1和链表2的内容。
  • 调用 mergeLinkedLists 函数合并链表1和链表2,并删除重复节点,结果存储在链表3中。
  • 打印合并后的链表3的内容。
  • 清理链表1、链表2 和链表3 中所有节点的内存,防止内存泄漏。
  • 返回0,表示程序正常结束。

示例运行

假设用户输入以下数据:

Enter the number of elements in LIST1: 5
Enter the elements of LIST1:
1 3 5 7 9
Enter the number of elements in LIST2: 4
Enter the elements of LIST2:
2 4 6 8
LIST1: 1 -> 3 -> 5 -> 7 -> 9 -> NULL
LIST2: 2 -> 4 -> 6 -> 8 -> NULL
Merged and deduplicated LIST3: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> NULL

在这个示例中:

  • 用户输入了链表1的5个节点的数据 [1, 3, 5, 7, 9]
  • 用户输入了链表2的4个节点的数据 [2, 4, 6, 8]
  • 打印链表1和链表2的内容。
  • 合并链表1和链表2,并删除重复节点,结果为 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> NULL

4.设双链表中的结点包括4个部分:前驱指针llink、后继指针rlink、数据域data、访问频度freq。初始时将各结点的freq设置为0。当对某结点访问时使该结点的freq增加1,并且将链表按照访问freq递减的顺序进行排序。请编写C语言算法实现以上功能。

#include <stdio.h>
#include <stdlib.h>

// 双链表节点定义
typedef struct Node {
int data;
int freq;
struct Node *llink;
struct Node *rlink;
} Node;

// 双链表定义
typedef struct {
Node *head;
Node *tail;
} DoublyLinkedList;

// 初始化双链表
void initDoublyLinkedList(DoublyLinkedList *list) {
list->head = NULL;
list->tail = NULL;
}

// 在双链表尾部插入节点
void insertAtTail(DoublyLinkedList *list, int value) {
Node *newNode = (Node *)malloc(sizeof(Node));
if (!newNode) {
printf("Memory error\n");
return;
}
newNode->data = value;
newNode->freq = 0;
newNode->llink = NULL;
newNode->rlink = NULL;

if (list->head == NULL) {
list->head = newNode;
list->tail = newNode;
} else {
list->tail->rlink = newNode;
newNode->llink = list->tail;
list->tail = newNode;
}
}

// 更新节点的频度并重新排序链表
void updateFreqAndSort(DoublyLinkedList *list, Node *node) {
node->freq++;

// 如果节点已经是第一个或者没有更高的频度节点,则不需要移动
if (node->llink == NULL || node->freq <= node->llink->freq) {
return;
}

// 从当前位置移除节点
node->llink->rlink = node->rlink;
if (node->rlink != NULL) {
node->rlink->llink = node->llink;
} else {
list->tail = node->llink;
}

// 找到合适的位置插入节点
Node *current = node->llink;
while (current->llink != NULL && current->freq < node->freq) {
current = current->llink;
}

if (current->llink == NULL) {
// 插入到头部
node->rlink = current;
node->llink = NULL;
current->llink = node;
list->head = node;
} else {
// 插入到中间
node->rlink = current;
node->llink = current->llink;
current->llink->rlink = node;
current->llink = node;
}
}

// 查找特定数据的节点
Node *findNode(DoublyLinkedList *list, int value) {
Node *current = list->head;
while (current != NULL) {
if (current->data == value) {
return current;
}
current = current->rlink;
}
return NULL;
}

// 打印双链表的内容
void printDoublyLinkedList(const DoublyLinkedList *list) {
Node *current = list->head;
while (current != NULL) {
printf("Data: %d, Freq: %d -> ", current->data, current->freq);
current = current->rlink;
}
printf("NULL\n");
}

int main() {
DoublyLinkedList list;
initDoublyLinkedList(&list);

// 插入一些节点
int n;
printf("Enter the number of nodes to insert: ");
scanf("%d", &n);

for (int i = 0; i < n; i++) {
int value;
printf("Enter data for node %d: ", i + 1);
scanf("%d", &value);
insertAtTail(&list, value);
}

printf("Initial List: ");
printDoublyLinkedList(&list);

// 访问节点并更新频度
int numAccesses;
printf("Enter the number of accesses: ");
scanf("%d", &numAccesses);

for (int i = 0; i < numAccesses; i++) {
int value;
printf("Enter data to access: ");
scanf("%d", &value);
Node *node = findNode(&list, value);
if (node != NULL) {
updateFreqAndSort(&list, node);
} else {
printf("Node with data %d not found.\n", value);
}
}

printf("Updated List: ");
printDoublyLinkedList(&list);

// 清理内存
Node *current = list.head;
while (current != NULL) {
Node *temp = current;
current = current->rlink;
free(temp);
}

return 0;
}

数据结构定义

// 双链表节点定义
typedef struct Node {
    int data;
    int freq;
    struct Node *llink;
    struct Node *rlink;
} Node;

// 双链表定义
typedef struct {
    Node *head;
    Node *tail;
} DoublyLinkedList;
  • Node 结构体定义了一个双链表节点,包含四个成员:
    • int data:存储节点的数据。
    • int freq:存储节点的访问频度。
    • struct Node *llink:指向前一个节点的指针。
    • struct Node *rlink:指向后一个节点的指针。
  • DoublyLinkedList 结构体定义了一个双链表,包含两个成员:
    • Node *head:指向双链表头节点的指针。
    • Node *tail:指向双链表尾节点的指针。

初始化双链表

// 初始化双链表
void initDoublyLinkedList(DoublyLinkedList *list) {
    list->head = NULL;
    list->tail = NULL;
}
  • 将双链表的头节点和尾节点初始化为 NULL,表示链表为空。

在双链表尾部插入节点

// 在双链表尾部插入节点
void insertAtTail(DoublyLinkedList *list, int value) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (!newNode) {
        printf("Memory error\n");
        return;
    }
    newNode->data = value;
    newNode->freq = 0;
    newNode->llink = NULL;
    newNode->rlink = NULL;

    if (list->head == NULL) {
        list->head = newNode;
        list->tail = newNode;
    } else {
        list->tail->rlink = newNode;
        newNode->llink = list->tail;
        list->tail = newNode;
    }
}
  • 创建一个新的节点 newNode,并分配内存。
  • 将新节点的数据设置为 value,并将频度 freq 初始化为0。
  • 将新节点的前后指针初始化为 NULL
  • 如果双链表为空(即 head 为 NULL),将新节点设置为头节点和尾节点。
  • 否则,将新节点插入到尾节点的后面,并更新尾节点的指针。

更新节点的频度并重新排序链表

// 更新节点的频度并重新排序链表
void updateFreqAndSort(DoublyLinkedList *list, Node *node) {
    node->freq++;

    // 如果节点已经是第一个或者没有更高的频度节点,则不需要移动
    if (node->llink == NULL || node->freq <= node->llink->freq) {
        return;
    }

    // 从当前位置移除节点
    node->llink->rlink = node->rlink;
    if (node->rlink != NULL) {
        node->rlink->llink = node->llink;
    } else {
        list->tail = node->llink;
    }

    // 找到合适的位置插入节点
    Node *current = node->llink;
    while (current->llink != NULL && current->freq < node->freq) {
        current = current->llink;
    }

    if (current->llink == NULL) {
        // 插入到头部
        node->rlink = current;
        node->llink = NULL;
        current->llink = node;
        list->head = node;
    } else {
        // 插入到中间
        node->rlink = current;
        node->llink = current->llink;
        current->llink->rlink = node;
        current->llink = node;
    }
}
  • 增加节点的频度 freq
  • 如果节点已经是第一个节点或者没有更高的频度节点,则不需要移动。
  • 否则,从当前位置移除节点:
    • 更新前一个节点的 rlink 指针。
    • 如果节点是尾节点,更新尾节点的指针。
  • 找到合适的位置插入节点:
    • 使用 while 循环找到第一个频度小于当前节点频度的节点。
    • 如果插入位置在头部,更新头节点的指针。
    • 否则,插入到中间位置,更新相关节点的指针。

查找特定数据的节点

// 打印双链表的内容
void printDoublyLinkedList(const DoublyLinkedList *list) {
    Node *current = list->head;
    while (current != NULL) {
        printf("Data: %d, Freq: %d -> ", current->data, current->freq);
        current = current->rlink;
    }
    printf("NULL\n");
}
  • 从头节点开始遍历双链表。
  • 如果找到数据等于 value 的节点,返回该节点。
  • 如果遍历完整个链表都没有找到,返回 NULL

打印双链表的内容

// 打印双链表的内容
void printDoublyLinkedList(const DoublyLinkedList *list) {
    Node *current = list->head;
    while (current != NULL) {
        printf("Data: %d, Freq: %d -> ", current->data, current->freq);
        current = current->rlink;
    }
    printf("NULL\n");
}
  • 从头节点开始遍历双链表。
  • 逐个打印每个节点的数据和频度。
  • 打印完所有节点后,输出一个换行符。

主函数

int main() {
    DoublyLinkedList list;
    initDoublyLinkedList(&list);

    // 插入一些节点
    int n;
    printf("Enter the number of nodes to insert: ");
    scanf("%d", &n);

    for (int i = 0; i < n; i++) {
        int value;
        printf("Enter data for node %d: ", i + 1);
        scanf("%d", &value);
        insertAtTail(&list, value);
    }

    printf("Initial List: ");
    printDoublyLinkedList(&list);

    // 访问节点并更新频度
    int numAccesses;
    printf("Enter the number of accesses: ");
    scanf("%d", &numAccesses);

    for (int i = 0; i < numAccesses; i++) {
        int value;
        printf("Enter data to access: ");
        scanf("%d", &value);
        Node *node = findNode(&list, value);
        if (node != NULL) {
            updateFreqAndSort(&list, node);
        } else {
            printf("Node with data %d not found.\n", value);
        }
    }

    printf("Updated List: ");
    printDoublyLinkedList(&list);

    // 清理内存
    Node *current = list.head;
    while (current != NULL) {
        Node *temp = current;
        current = current->rlink;
        free(temp);
    }

    return 0;
}
  • 初始化一个双链表 list
  • 提示用户输入要插入的节点数量 n
  • 提示用户输入每个节点的数据,并调用 insertAtTail 函数将其插入到双链表中。
  • 打印初始双链表的内容。
  • 提示用户输入要访问的次数 numAccesses
  • 对于每次访问,提示用户输入要访问的节点数据,调用 findNode 函数查找节点,如果找到则调用 updateFreqAndSort 函数更新节点的频度并重新排序链表。
  • 打印更新后的双链表的内容。
  • 清理双链表中所有节点的内存,防止内存泄漏。
  • 返回0,表示程序正常结束。

示例运行

假设用户输入以下数据:

Enter the number of nodes to insert: 5
Enter data for node 1: 3
Enter data for node 2: 1
Enter data for node 3: 4
Enter data for node 4: 1
Enter data for node 5: 5
Initial List: Data: 3, Freq: 0 -> Data: 1, Freq: 0 -> Data: 4, Freq: 0 -> Data: 1, Freq: 0 -> Data: 5, Freq: 0 -> NULL
Enter the number of accesses: 3
Enter data to access: 1
Enter data to access: 4
Enter data to access: 1
Updated List: Data: 1, Freq: 2 -> Data: 4, Freq: 1 -> Data: 1, Freq: 1 -> Data: 3, Freq: 0 -> Data: 5, Freq: 0 -> NULL

在这个示例中:

  • 用户输入了5个节点的数据 [3, 1, 4, 1, 5]
  • 初始双链表为 Data: 3, Freq: 0 -> Data: 1, Freq: 0 -> Data: 4, Freq: 0 -> Data: 1, Freq: 0 -> Data: 5, Freq: 0 -> NULL
  • 用户进行了3次访问,访问的数据分别为 141
  • 更新后的双链表为 Data: 1, Freq: 2 -> Data: 4, Freq: 1 -> Data: 1, Freq: 1 -> Data: 3, Freq: 0 -> Data: 5, Freq: 0 -> NULL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值