C语言入门笔记整理 08 链表

链表

算法:
通俗定义:

解题的 方法 和 步骤。

狭义的定义:

对存储数据的操作。

广义的定义:

泛型

泛型: 无论 数据是 如何存储,我们对该数据的操作都是一样的。

我们至少可以通过 两种 数据结构 来存储数据

数组

优点:
	存取速度快
缺点:
	需要一个连续很大的内存
	插入和删除元素的效率很低

链表

优点:
	插入元素效率高
	不要一个连续很大的内存
缺点:
	查找某个位置的元素 效率低

数据结构:
如何将 现实中 复杂的问题,转化为 计算机中的数据 进行存储。

链表专业术语:

/*
头结点: 头结点的数据类型 和 首节点的数据类型 是一模一样,
头结点 是首节点前面,
头结点 并不存放有需要数据,
设置头结点的目的: 方便 对 链表的操作

头指针: 存放头结点 地址的 指针变量。
首节点: 存放第一个有效数据的节点
尾节点: 存放最后一个有效数据的节点

可以说:首节点是车厢,头结点就是牵引车厢的火车头,头指针就是贴在火车头上的编码
*/
在这里插入图片描述

/*
 头结点:  头结点的数据类型 和 首节点的数据类型 是一模一样,
         头结点 是首节点前面,
         头结点 并不存放有需要数据,
         设置头结点的目的: 方便 对 链表的操作
 
 头指针: 存放头结点 地址的 指针变量。
 首节点: 存放第一个有效数据的节点
 尾节点: 存放最后一个有效数据的节点
 
 可以说:首节点是车厢,头结点就是牵引车厢的火车头,头指针就是贴在火车头上的编码
 */

// 定义了一个链表节点的数据类型

struct Node{
    int data;
    struct Node * pNext;
};

int main(void){
        
    
    return 0;
}

确定一个链表需要1个参数就可以

头指针 就可以了


#include <stdio.h>

struct Node{
    int data;
    struct Node * pNext;
};


struct Node * CreateList(){
    
    return pHead;
}

int main(void){
        
    struct Node * pHead; // pHead指针 用来存放 链表头结点的地址
    
    pHead = CreatList();
    TraverseList(pHead);
    
    return 0;
}

完整版 链表

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


struct Node{
    int data; // 数据域
    struct Node * pNext; // 指针域
};


struct Node * CreateList(void){
    int len; // 用来存放有效节点的个数
    int i;
    int val; // 用来临时存放用户输入的结点的值

    // 分配了一个不存放有效数据的头结点
    struct Node * pHead = (struct Node *)malloc(sizeof(struct Node));
    
    struct Node * pTail = pHead;
    pTail->pNext = NULL;

    printf("请输入您需要生成的链表节点的个数: len = ");
    scanf("%d", &len);

    for (i = 0; i < len; ++i) {
        printf("请输入第%d个节点的值: ", i+1);
        scanf("%d", &val);

        struct Node * pNew = (struct Node *)malloc(sizeof(struct Node));
        if (NULL == pNew) {
            printf("分配失败,程序终止!\n");
            exit(-1);
        }
            pNew->data = val;
            pTail->pNext = pNew;
            pNew->pNext = NULL;
            pTail = pNew;
        }
     
    return pHead;
}

bool EmptyList(struct Node * pHead){
    if (pHead->pNext == 0) { // pHead->pNext等价于 (*pHead).pNext
        return true;
    } else{
        return false;
    }
}


void TraverseList(struct Node * pHead){
    struct Node * p = pHead->pNext;
    
    if (EmptyList(pHead)) {
        printf("链表为空!\n");
    }

    
    while (p!= NULL) {
        printf("%d\n", p->data);
        p = p->pNext;
    }

    return;
}


int main(void){
    struct Node * pHead; // pHead指针 用来存放 链表头结点的地址

    pHead = CreateList(); //CreatList功能:创建一个非循环 单链表,并将链表 头结点 地址 返还给pHead
    TraverseList(pHead); // 把每个元素都输出

    return 0;
}

总结

狭义算法:

算法是 依附于 存储结构的
不同的 存储结构,所执行的算法是不一样的!

广义算法:
广义的算法也叫泛型

无论数据是如何存储的,对该数据的操作都是一样的。

即 站在更高的维度,数组 和 链表 都是线性结构
都是 输出 第一个元素,第二个元素,第三个元素,这样。

位运算符:

& 按位与
&& 叫 逻辑与 也叫并且
| 按位或
|| 叫 逻辑或
^
>>
<<
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>


int main(void)
{
    int i = 5;
    int j = 7;
    int k;
    
    k = i & j;
    // 0101
    // 0111
    // 0101  是5
    
    /*
     1 & 1 = 1
     1 & 0 = 0
     0 & 1 = 0
     0 & 0 = 0
     */
    
    printf("%d\n",k); // 5
    
    k = i && j;
    printf("%d\n",k); // k的值只能是1或0,因为&&是逻辑运算符。逻辑运算符的结果只能是 真 或 假。 // 1
    
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>


int main(void)
{
    int i = 5;
    int j = 7;
    int k;
    
    k = i | j;
    // 0101
    // 1101
    // 1101  结果为7
    // 1|0 = 1
    // 1|1 = 1
    // 0|1 = 1
    // 0|0 = 0
    
    printf("%d\n",k); // 7
    
    k = i || j;
    printf("%d\n",k); // k的值只能是1或0,因为&&是逻辑运算符。逻辑运算符的结果只能是 真 或 假。 // 1
    
    return 0;
}

按位取反


int main(void)
{
    int i = 5;
    int j = 7;
    int k;
    
    k = ~i; //  ~i: 把i变量所有的二进制取反
    /*
     i 1001
     k 0110 前面补1
     */
    
    printf("%d\n",k); // -6
    
    k = i || j;
    printf("%d\n",k); // k的值只能是1或0,因为&&是逻辑运算符。逻辑运算符的结果只能是 真 或 假。 // 1
    
    return 0;
}

int main(void)
{
    int i = 5;
    int j = 7;
    int k;
    
    k = i ^ j;
    /*
     相同为零
     不同为1
     1 ^ 0 = 1
     0 ^ 1 = 1
     1 ^ 1 = 1
     0 ^ 0 = 0
     */
    // 1001
    // 1011
    // 0010
    
    printf("%d\n",k); // 2
    
    k = i || j;
    printf("%d\n",k); // k的值只能是1或0,因为&&是逻辑运算符。逻辑运算符的结果只能是 真 或 假。 // 1
    
    return 0;
}
int main(void)
{
    int i = 5;
    int j = 7;
    int k;
    
    k = i << 2;
    /*
     i << 1 表示把i的所有二进制 往左移 一位
     左移n位 相当于 乘以 2的n次方
     */
    
    printf("%d\n",k); // 5 x 4 = 20
    
    k = i || j;
    printf("%d\n",k); // k的值只能是1或0,因为&&是逻辑运算符。逻辑运算符的结果只能是 真 或 假。 // 1
    
    return 0;
}

左移

int main(void)
{
    int i = 5;
    int j = 7;
    int k;
    
    k = i << 2; // 把i的所有二进制位左移2位,右边补零
    /*
     i << 1 表示把i的所有二进制 往左移 一位
     左移n位 相当于 乘以 2的n次方
     */
    
    printf("%d\n",k); // 5 x 4 = 20
    

    return 0;
}
int main(void)
{
    int i = 5;
    int k;
    
    k = i >> 2; // 把i的所有二进制位右移2位,左边补零
    /*
     右移动 相当于 除以2的n次方
     前提是数据不能 丢失
     */
    
    printf("%d\n",k); // 5 ➗ 4 = 1
    

    return 0;
}

位运算负的现实意义:

通过位运算符我们可以对数据的操作精确到每一位

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值