数据结构和算法

所用语言——C语言

数据结构

数据结构就是数据存放的思想

数组

特点:元素是连续的

缺点:增、删元素很复杂

链表

链表的概念

链表是很多结构体通过存放下一结构体指针地址的数据结构。

特点:链表各节点的地址是不连续的

初始化链表

#include <stdio.h>
#include <stdlib.h>
// 1.定义链表节点结构体
struct Node{
    int data;//数据域
    struct Node *next;//指针域
};
int main()
{
    // 2.初始化各节点
    struct Node node1 = {1,NULL};
    struct Node node2 = {2,NULL};
    struct Node node3 = {3,NULL};
    // 3.连接各节点
    node1.next = &node2;
    node2.next = &node3;
    // 4.通过首节点打印整个链表内容
    printf("%d\t%d\t%d",node1.data,node1.next->data,node1.next->next->data);
    return 0;
}

链表的遍历

通过链表头遍历整个链表;不同于遍历数组通过for循环中下标的递增来遍历,遍历链表通过while循环中指针指向的变更来遍历

#include <stdio.h>
#include <stdlib.h>
struct Node{
    int data;
    struct Node *next;
};
// 传入链表头遍历链表
void printLink(struct Node *head){
    struct Node *point;
    point = head;
    while(point != NULL){
        printf("%d ",point->data);
        // 打印完数据域指针移到下一个节点
        point = point->next;
    }
    putchar('\n');
}
int main()
{
    struct Node node1 = {1,NULL};
    struct Node node2 = {2,NULL};
    struct Node node3 = {3,NULL};
    struct Node node4 = {4,NULL};

    node1.next = &node2;
    node2.next = &node3;
    node3.next = &node4;
    
    printLink(&node1);
    return 0;
}

统计链表节点个数及链表查找

查询链表中是否有data这个数据,有的话返回1没有返回0

#include <stdio.h>
#include <stdlib.h>
struct Node{
    int data;
    struct Node *next;
};
void printLink(struct Node *head){
    struct Node *point;
    point = head;
    while(point != NULL){
        printf("%d ",point->data);
        point = point->next;
    }
    putchar('\n');
}
// 统计链表节点个数
int getLinkTotalNodeNum(struct Node *head){
    int cnt = 0;
    while(head != NULL){
        cnt++;
        head = head->next;
    }
    return cnt;
}
// 查找数据
int searchLink(struct Node *head,int data){
    while(head != NULL){
        if(head->data == data){
            return 1;
        }
        head = head->next;
    }
    return 0;
}
int main()
{
    struct Node node1 = {1,NULL};
    struct Node node2 = {2,NULL};
    struct Node node3 = {3,NULL};
    struct Node node4 = {4,NULL};

    node1.next = &node2;
    node2.next = &node3;
    node3.next = &node4;
    
    printLink(&node1);
    
    int ret = getLinkTotalNodeNum(&node1);
    printf("total num = %d\n",ret);
    
    ret = searchLink(&node1,1);
    if(ret == 0){
        printf("no 1");
    }else{
        printf("have 1");
    }
    return 0;
}

从指定节点后插入新节点

先将新节点指向原节点的下一个节点,再让原节点指向新节点。注意:函数参数尽量传指针,直接传结构体啊哈C会出错

如果有链表节点的数据重复还能插入新节点吗?

#include <stdio.h>
#include <stdlib.h>
struct Node{
    int data;
    struct Node *next;
};
// 遍历链表
void printLink(struct Node *head){
    struct Node *point;
    point = head;
    while(point != NULL){
        printf("%d ",point->data);
        point = point->next;
    }
    putchar('\n');
}
// 在指定节点后插入新节点
int insertFromBehind(struct Node *head, int data, struct Node *new){
    struct Node *p = head;
    while(p != NULL){
        if(p->data == data){
            new->next = p->next;
            p->next = new;
            return 1;
        }
        p = p->next;
    }
    return 0;
}
int main()
{
    struct Node node1 = {1,NULL};
    struct Node node2 = {2,NULL};
    struct Node node3 = {3,NULL};
    struct Node node4 = {4,NULL};
    struct Node new = {100,NULL};

    node1.next = &node2;
    node2.next = &node3;
    node3.next = &node4;
    
    insertFromBehind(&node1,3,&new);
    printLink(&node1);//1 2 3 100 4
    
    return 0;
}

从指定节点前插入新节点

为什么要有返回值为结构体指针?不能是void吗?

因为链表头也有可能被改变

#include <stdio.h>
#include <stdlib.h>
struct Node{
    int data;
    struct Node *next;
};
// 遍历链表
void printLink(struct Node *head){
    struct Node *point;
    point = head;
    while(point != NULL){
        printf("%d ",point->data);
        point = point->next;
    }
    putchar('\n');
}
// 从节点前插入新节点
struct Node* insertFromfor(struct Node *head, int data, struct Node *new){
    struct Node *p = head;
    if(p->data == data){
        new->next = head;
        return new;
    }
    while(p->next != NULL){
        if(p->next->data == data){
            new->next = p->next;
            p->next = new;
            return head;
            //一定要在这里return head,因为不return下一句p指向的永远是新节点,新节点的next节点中data永远等于data,会一直进到if中,即在data前一直插入新节点
        }
        p = p->next;
    }
    return head;
}
int main()
{
    struct Node node1 = {1,NULL};
    struct Node node2 = {2,NULL};
    struct Node node3 = {3,NULL};
    struct Node node4 = {4,NULL};
    struct Node new = {100,NULL};

    node1.next = &node2;
    node2.next = &node3;
    node3.next = &node4;
    
    struct Node *head = NULL;
    head = &node1;
    head = insertFromfor(head, 2, &new);
    printLink(head);//1 100 2 3 4
    return 0;
}

链表删除指定节点

#include <stdio.h>
#include <stdlib.h>
struct Node{
    int data;
    struct Node *next;
};
void printLink(struct Node *head){
    struct Node *point;
    point = head;
    while(point != NULL){
        printf("%d ",point->data);
        point = point->next;
    }
    putchar('\n');
}
// 删除指定节点
struct Node* deleteNode(struct Node *head, int data){
    struct Node *p = head;
    if(p->data == data){
        head = head->next;
        // free(p);动态创建链表用malloc函数时可以用free
        return head;
    }
    while(p->next != NULL){
        if(p->next->data == data){
            p->next = p->next->next;
            return head;
            //这里return掉是因为防止最后一个节点是NULL后,没有p->next无法进行while判断导致程序崩溃
        }
        //这里的遍历只为找if的条件
        p = p->next;
    }
    return head;
}
int main()
{
    struct Node node1 = {1,NULL};
    struct Node node2 = {2,NULL};
    struct Node node3 = {3,NULL};
    struct Node node4 = {4,NULL};

    node1.next = &node2;
    node2.next = &node3;
    node3.next = &node4;
    struct Node *head = &node1;
    printLink(head);
    head = deleteNode(head, 2);
    printLink(head);
    return 0;
}

链表动态创建之头插法

不断在链表的头部插入新节点

#include <stdio.h>
#include <stdlib.h>
struct Node{
    int data;
    struct Node *next;
};
void printLink(struct Node *head){
    struct Node *point;
    point = head;
    while(point != NULL){
        printf("%d ",point->data);
        point = point->next;
    }
    putchar('\n');
}
// 头插法
struct Node* insertFromHead(struct Node *head){
    struct Node *newNode;
    while(1){
        newNode = (struct Node *)malloc(sizeof(struct Node));
        // 不要出现野指针,要给next初始化为NULL
        newNode->next = NULL;
        printf("请输入新节点的数据:");
        scanf("%d",&(newNode->data));
        if(newNode->data == 0){
            printf("0 quit\n");
            return head;
        }
        if(head == NULL){
            head = newNode;
        }else{
            newNode->next = head;
            head = newNode;
        }
    }
    return head;
}
int main()
{
    struct Node *head = NULL;
    head = insertFromHead(head);
    printLink(head);
    return 0;
}

头插法优化


尾插法创建链表

从链表的尾部不断插入新节点

#include <stdio.h>
#include <stdlib.h>
struct Node{
    int data;
    struct Node *next;
};
// 打印链表
void printLink(struct Node *head){
    struct Node *node = head;
    while(node != NULL){
        printf("%d\t",node->data);
        node = node->next;
    }
    putchar('\n');
}
// 尾插法不断插入新节点
struct Node* insertFromTail(struct Node *head){
    struct Node *node = head;
    struct Node *newNode = NULL;
    while(1){
        newNode = (struct Node *)malloc(sizeof(struct Node));
        newNode->data = 0;
        newNode->next = NULL;
        printf("请输入要插入的节点数据:");
        scanf("%d",&newNode->data);
        if(newNode->data == 0){
            return head;
        }
        if(head == NULL){
            head = newNode;
            node = head;
        }else{
            // 在任意链表后插入新节点都可以
            // 将node定位到链表的最后一位
            while(node != NULL){
                if(node->next == NULL){
                    break;
                }
                node = node->next;
            }
            node->next = newNode;
            node = newNode;
        }
    }
    return head;
}
int main()
{
    // 用尾插法不断插入新节点
    struct Node *head = NULL;
    head = insertFromTail(head);
    // 打印链表
    printLink(head);
    return 0;
}

链表综合

#include <stdio.h>
#include <stdlib.h>
#define GET_RESULT 1
typedef struct Node{
    int data;
    struct Node *next;
}Node;
// 遍历链表
void printLink(Node *head){
    Node *node = head;
    // printf("链表:");
    if(head == NULL){
        printf("NULL");
    }
    while(node != NULL){
        printf("%d\t",node->data);
        node = node->next;
    }
    putchar('\n');
}
// 统计链表节点个数
int getNodeNum(Node *head){
    int count = 0;
    Node *node = head;
    while(node != NULL){
        count++;
        node = node->next;
    }
    return count;
}
// 链表查找
int searchLink(Node *head, int data){
    Node *node = head;
    while(node != NULL){
        if(node->data == data){
            return 1;
        }
        node = node->next;
    }
    return 0;
}
// 从指定节点后插入新节点
Node* insertFromBehind(Node *head, int data, Node *newNode){
    Node *node = head;
    if(head == NULL){
        head = newNode;
        return head;
    }
    while(node != NULL){
        if(node->data == data){
            newNode->next = node->next;
            node->next = newNode;
            return head;
        }
        node = node->next;
    }
    return head;
}
// 从指定节点前插入新节点
Node* insertFromForward(Node *head, int data, Node *newNode){
    Node *node = head;
    if(head == NULL){
        head = newNode;
        return head;
    }
    if(head->data == data){
        newNode->next = head;
        head = newNode;
        return head;
    }
    while(node->next != NULL){
        if(node->next->data == data){
            newNode->next = node->next;
            node->next = newNode;
            return head;
        }
        node = node->next;
    }
    return head;
}
// 不断删除指定节点
Node* deleteNode(Node *head){
    int data = 0;
    Node *node = head;
    while(1){
        printf("请输入要删除的节点:");
        scanf("%d",&data);
        if(data == 0){
            return head;
        }
        if(head->data == data){
            head = head->next;
            node = head;
            continue;
        }
        while(node->next != NULL){
            if(node->next->data == data){
                node->next = node->next->next;
                break;
            }
            node = node->next;
        }
        node = head;
    }
}
// 头插法
Node* insertFromHead(Node *head){
    Node *newNode;
    while(1){
        newNode = (Node *)malloc(sizeof(Node));
        newNode->data = 0;
        newNode->next = NULL;
        printf("请输入头插法要插入的新节点数据:");
        scanf("%d",&newNode->data);
        if(newNode->data == 0){
            return head;
        }
        if(head == NULL){
            head = newNode;
        }else{
            newNode->next = head;
            head = newNode;
        }
    }
}
// 尾插法
Node* insertFromTail(Node *head){
    Node *newNode;
    Node *node = head;
    while(1){
        newNode = (Node *)malloc(sizeof(Node));
        newNode->data = 0;
        newNode->next = NULL;
        printf("请输入尾插法要插入的新节点数据:");
        scanf("%d",&newNode->data);
        if(newNode->data == 0){
            return head;
        }
        if(head == NULL){
            head = newNode;
            node = head;
        }else{
            while(node != NULL){
                if(node->next == NULL){
                    break;
                }
                node = node->next;
            }
            node->next = newNode;
            node = newNode;
        }
    }
}
int main()
{
    // 初始化链表
    Node node1 = {1,NULL};
    Node *head = &node1;
    Node node2 = {2,NULL};
    Node node3 = {3,NULL};
    head->next = &node2;
    node2.next = &node3;
    // 遍历链表
    printLink(head);
    // 统计链表节点个数
    int nodeNum = getNodeNum(head);
    printf("节点有%d个\n",nodeNum);
    // 链表查找
    int data = 0;
    printf("请输入要查找的节点:");
    scanf("%d",&data);
    int result = searchLink(head,data);
    if(result == GET_RESULT){
        printf("存在该节点\n");
    }else{
        printf("该节点不存在\n");
    }
    // 从指定节点后插入新节点
    printf("请输入要从哪个节点后插入新节点:");
    scanf("%d",&data);
    Node newNode1 = {101,NULL};
    head = insertFromBehind(head,data,&newNode1);
    printLink(head);
    // 从指定节点前插入新节点
    printf("请输入要从哪个节点前插入新节点:");
    scanf("%d",&data);
    Node newNode2 = {100,NULL};
    head = insertFromForward(head,data,&newNode2);
    printLink(head);
    // 不断删除指定节点
    head = deleteNode(head);
    printLink(head);
    // 头插法
    head = insertFromHead(head);
    printLink(head);
    // 尾插法
    head = insertFromTail(head);
    printLink(head);
    return 0;
}

基础算法

冒泡排序

给定一个数组nums,有numsSize个元素,将其元素从小到大排序

//将数组中前一个元素和后一个元素比较,如果后面的元素更大,就交换元素位置,以此类推

//比如nums = {5,4,3,2,1};
//第1轮比较了4次,最大值5被排到了最后
//第2轮比较了3次,此轮的最大值4被排到了倒数第2位
//以此类推,用i代表第几轮比较,j代表第几次比较
//共比较了numsSize - 1轮,每一轮比较了numsSize - i次
void bubbleSort(int* nums, int numsSize){
    int temp, i, j;
    for (i = 1; i <= numsSize - 1; i++) {
        for(j = 1; j <= numsSize - i; j++){
            if(nums[j - 1] > nums[j]){
                temp = nums[j];
                nums[j] = nums[j - 1];
                nums[j - 1] = temp;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值