数据结构与算法之美学习笔记(二):链表

链表

链表与数组区别:

  从底层的存储结构上来看,数组需要一块连续的内存空间来存储,对内存的要求比较高。如果我们申请一个100MB大小的数组,当内存中没有连续的、足够大的存储空间时,即便内存的剩余总可用空间大于100MB,仍然会申请失败。 而链表恰恰相反,它并不需要一块连续的内存空间,它通过“指针”将一组零散的内存块串联起来使用,所以如果我们申请的是100MB大小的链表,根本不会有问题。

  链表结构五花八门,三种最常见的链表结构:单链表、双向链表和循环链表。

  链表插入和删除不需要搬运数据,只要修改指针,所以时间复杂度为O(1)。但是链表要想随机访问第k个元素,没有数组那么高效了。因为链表中的数据并非连续存储的,所以无法像数组那样,根据首地址和下标,通过寻址公式就能直接计算出对应的内存地址,而是需要根据指针一个结点一个结点地依次遍历,直到找到相应的结点。

  单链表的基本操作(头插法/尾插法创建单链表、插入、删除),删除链表倒数第k个结点以及合并两个有序链表:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
/*
 *  单链表结构体定义;
 *  头插法/尾插法;
 *  插入、删除;
* 删除倒数第k个结点
* 归并两个有序链表
*/ //单链表结构体 typedef struct LinkList { int data; LinkList* next; }Node; Node* init_createa(int n) { Node *head, *p, *q; head = (Node *)malloc(sizeof(Node)); head->data = NULL; head->next = NULL; q = head; for (int i = 0; i < n; i++) { p = (Node *)malloc(sizeof(Node)); p->data = 2 * i + 1; p->next = NULL; q->next = p; q = p; } return head; } Node* init_createb(int n) { Node *head, *p, *q; head = (Node *)malloc(sizeof(Node)); head->data = NULL; head->next = NULL; q = head; for (int i = 0; i < n; i++) { p = (Node *)malloc(sizeof(Node)); p->data = 2 * i; p->next = NULL; q->next = p; q = p; } return head; } //尾插法初始单链表 Node* init_tailcreate(int n) { Node *head, *p, *q; head = (Node *)malloc(sizeof(Node)); head->data = NULL; head->next = NULL; q = head; for (int i = 0; i < n; i++) { p = (Node *)malloc(sizeof(Node)); p->data = 2 * i + 1; p->next = NULL; q->next = p; q = p; } return head; } //头插法初始单链表 Node* init_headcreate(int n) { Node *head, *p, *q; head = (Node *)malloc(sizeof(Node)); head->data = NULL; head->next = NULL; q = head; while(n) { p = (Node *)malloc(sizeof(Node)); p->data = n; p->next = NULL; p->next = q->next; q->next = p; n--; } return head; } //在链表位置pos后插入数据 Node* insert_data(Node *head_node, int pos, int data) { Node *p, *q; p = head_node; q = (Node *)malloc(sizeof(Node)); q->data = data; q->next = NULL; while (pos--) { p = p->next; } q->next = p->next; p->next = q; return head_node; } //删除pos后的数据 Node* delete_data(Node* head_node, int pos) { Node *p, *q; p = head_node; while (pos--) { p = p->next; } q = p->next; p->next = q->next; q->next = NULL; free(q); return head_node; } //删除倒数第pos个的数据 Node* delete_data_intail(Node* head_node, int pos) { Node *p, *q; p = head_node; q = head_node; while (pos--) { p = p->next; } while (p->next != NULL) { q = q->next; p = p->next; } Node *tem = q->next; q->next = q->next->next; tem->next = NULL; free(tem); return head_node; } //合并两个有序链表 Node* merge_sort_list(Node* head_a, Node* head_b) { Node *a, *b, *head, *p; a = head_a->next; b = head_b->next; head = (Node *)malloc(sizeof(Node)); head->data = NULL; head->next = NULL; p = head; while(a != NULL && b != NULL) { if ( a->data < b->data) { p->next = a; a = a->next; } else if ( b->data < a->data) { p->next = b; b = b->next; } p = p->next; } if (a != NULL) p->next = a; if (b != NULL) p->next = b; return head->next; } //打印单链表数据 void show_linklist(Node* head_node) { while (head_node != NULL) { std::cout << "data:" << head_node->data << std::endl; head_node = head_node->next; } } int main() { Node *head, *p, *q; int n = 5; //std::cin >> n; head = init_tailcreate(n); q = head; std::cout << "ori::" << std::endl; show_linklist(q); q = insert_data(head, 3, 10); std::cout << "insert::" << std::endl; show_linklist(q); q = delete_data(head, 3); std::cout << "delete::" << std::endl; show_linklist(q); std::cout << std::endl; q = delete_data_intail(head, 3); std::cout << "delete::" << std::endl; show_linklist(q); std::cout << std::endl; Node *head_a = init_createa(5); show_linklist(head_a); std::cout << std::endl; Node *head_b = init_createb(7); show_linklist(head_b); std::cout << std::endl; Node *merge_head = merge_sort_list(head_a, head_b); std::cout << "merge linklist:" << std::endl; show_linklist(merge_head); return 0; }

 

链表判断是否为回文串(需用到反转链表,递归反转链表、迭代反转链表):

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


char word_array[] = {'a', 'b', 'a', 'b', 'b', 'a', 'b', 'a'};  //回文字符串

//定义结构体
typedef struct LinkList {
    char data;
    LinkList *next;
}pNode;

//初始化回文链表
pNode* init_list(int n) {
    pNode *head, *p, *q;
    head = (pNode*)malloc(sizeof(pNode));
    head->data = NULL;
    head->next = NULL;
    for (int i = 0; i < n; i++) {
        p = (pNode *)malloc(sizeof(pNode));
        p->data = word_array[i];
        p->next = NULL;
        if (head->next == NULL) {
            head->next = p;
        }
        else {
            q->next = p;
        }
        q = p;
    }
    return head;

}

//显示链表数据
void show_data(pNode* head) {
    pNode *curhead;
    curhead = head;
    while (curhead != NULL) {
        std::cout << "data:" << curhead->data << std::endl;
        curhead = curhead->next;
    }
}

//递归反转链表
pNode* reverse_list(pNode* p_head) {
    pNode *head;
    if (p_head->next == NULL || p_head == NULL)
        return p_head;
    head = reverse_list(p_head->next);
    p_head->next->next = p_head;
    p_head->next = NULL;
    return head;
}

//迭代反转链表
pNode* reverse_list_by_iteratino(pNode* p_head) {
    pNode *head, *next_node, *tem_node;
    if (p_head->next == NULL || p_head == NULL)
        return p_head;
    head = NULL;
    next_node = p_head;
    while (next_node) {
        tem_node = next_node->next;
        next_node->next = head;
        head = next_node;
        next_node = tem_node;
    }
    return head;
}


int main(){

    pNode *head = NULL, *q, *p;
    head = (pNode*)malloc(sizeof(pNode));
    head->data = NULL;
    head->next = NULL;
    int n = sizeof(word_array);  //求字符串长度
    int mid_node_index = 0;
    mid_node_index = n / 2;     //找中点位置
    int tem = mid_node_index;
    head = init_list(n);
    q = head->next;
    p = head->next;

    if (n == 1) {
        std::cout << "true." << std::endl;
    }
    else {
    if (n % 2 == 0 ) {
        while (tem--) {
            q = q->next;
        }
        q = reverse_list(q);                 //递归反转链表 
//        q = reverse_list_by_iteratino(q);  //迭代反转链表
    }
    else {
        while (tem--) {
            q = q->next;
        }
        q = q->next;
        q = reverse_list(q);
//        q = reverse_list_by_iteratino(q);
    }
    bool flag = true;
    for (int i = 0; i < mid_node_index; i++) {
        if (p->data != q->data) {
            flag = false;
            std::cout << "false." << std::endl;
            break;
        }
        p = p->next;
        q = q->next;
    }
    if (flag == true)
        std::cout << "true." << std::endl;
    }
    return 0;
}

快慢指针判断链表是否有环、寻找链表中间结点。

思想:快指针每次走两步,慢指针每次走一步。当链表中有环时,快指针先进环,慢指针后进,慢指针没在环中走完一圈时,快指针一定能追上慢指针。

找中间节点时,快指针走完整个链表,慢指针只走了一半,此时慢指针指向的结点即为中间结点。

//判断链表是否有环
bool check_circle(pNode *p_head) {
    pNode *slow_node = p_head, *fast_node = p_head;
    if (p_head == NULL || p_head->next == NULL)
        return false;
    while (fast_node->next != NULL && fast_node->next->next != NULL) {
        slow_node = slow_node->next;
        fast_node = fast_node->next->next;

        if(slow_node == fast_node) {
            return true;
        }
    }
    return false;
}

//寻找链表中间结点
pNode* middle_node(pNode* p_head) {
    pNode *slow_node = p_head, *fast_node = p_head;
    if(p_head == NULL || p_head->next == NULL)
        return p_head;
    while(fast_node->next != NULL && fast_node->next->next != NULL) {
        fast_node = fast_node->next->next;
        slow_node = slow_node->next;
    }
    return slow_node;
}
int main(){

    pNode *head = NULL, *q, *p;
    head = (pNode*)malloc(sizeof(pNode));
    head->data = NULL;
    head->next = NULL;
    
    head = init_list(n);
   
    pNode *circle_head, *c1, *c2;    // 创建一个带环链表 circle_head->a->B->a
    circle_head->data = NULL;
    circle_head->next = NULL;
    c1 = (pNode*)malloc(sizeof(pNode));
    c1->data = 'a';
    c1->next = NULL;
    if (circle_head->next == NULL)
       circle_head->next = c1;
    c2 = c1;
    c1 = (pNode*)malloc(sizeof(pNode));
    c1->data = 'B';
    c1->next = NULL;
    c2->next = c1;
    c2 = c1;
    c2->next = circle_head->next;
    std::cout << check_circle(circle_head) << std::endl;  //判断是否有环,有1,否0;
    pNode *temm = middle_node(head->next);   //返回链表中间结点。

    return 0;
}

 

posted @ 2021-04-22 19:01  与囡  阅读(49)  评论(0编辑  收藏  举报