10.补码+位运算符+NULL+链表

本文详细介绍了补码的概念及转换方法,包括正负整数的二进制表示,并讲解了位运算符的功能与应用场景。此外,还探讨了链表的基本概念与实现。
【补码】
				在vc++6.0中一个int类型的变量所能存储的数字的范围是多少
				最小负数的二进制代码是多少
				最大正数的二进制代码是多少
				已知一个整数的二级制代码求出原始的数字
				数字超过最大正数会怎样

				原码
					也叫 符号-绝对值码
					最高位0表示正 1表示负,其余二进制位是该数字的绝对值的二进制位

					原码简单易懂
					加减运算复杂
					存在加减乘除四种运算,增加了CPU的复杂度
					零的表示不唯一

				反码
					反码运算不便,也没有在计算机中应用
				移码
					表示数值平移N位,N称为移码量
					移码主要用于浮点数的阶码的存储
				补码
					已知十进制转二进制
						求正整数转二进制
							除2取余,直至商为零,余数倒序排序
						求负整数转二进制
							先求与该负数相对应的正整数的二进制代码,然后将
							所有位取反,末尾加1,不够所属变量类型字节数的位数时,左边补1
							举例:int -3
								先求3的的二进制码为 011
								取反为	100
								末尾加1为 101
								因为是整型变量为4个字节数,即4X8=32位,而上面只占了3位,所以左边需要补29个零
								最终为:11111111111111111111111111111101
						求零的二进制
							全是零

					已知二进制求十进制
						如果首位是0,则表明是正整数,按普通方法来求
						如果首位是1,则表明是负整数,将所有位取反,末尾加1,所得数字就是该负数的绝对值
						如果全是零,则对应的十进制数字就是零
			进制转化
				进制即时逢几进一
				比如,N进制就是逢N进一
				计算机只识别二进制
				而人们常用的习惯使用的是十进制
				----------------------------------------
				在数字后面加B表示二进制
							O表示八进制
							D表示十进制
							H表示十六进制
【位运算符】
			&   按位与
					&& 逻辑与 也叫并且
					&&与& 的含义完全不同
					1&1 = 1
					1&0 = 0
					0&0 = 0
					0&1 = 0

			|	
				||逻辑或
				| 按位或	
					1|1 = 1
					1|0 = 1
					0|0 = 0
					0|1 = 1
			~	
				按位取反
				~i就是把i变量所有的二进制位取反

			^
				按位异或
				相同为零,不同为1
				1 ^ 0 = 1
				0 ^ 1 = 1
				1 ^ 1 = 0
				0 ^ 0 = 0

			<<
				按位左移
				i >> 3 表示把i的所有二进制位左移3位,右边补零

				左移n位相当于乘以2的n次方

				面试题:
					A) i = i*8;
					B) i = i << 3;
					请问上述两个语句,哪个语句执行的速度快
					答案:B快
					因为如果是乘法,在计算机中运算的时候会需要调用到很多复杂的东西,
					而位移却是不用,所以位移执行快。i << 3 = i * 2^3 (i乘以2的3次方)
			>>
				按位右移
				i >> 3 表示把i的所有二进制位右移3位,左边一般是0,也可能根据最高位是1或者0

				右移n位相当于除以2的n次方,前提是不能溢出,数据不能移的丢失了
				
				面试题:
					A) i = i/8;
					B) i = i >> 3;
					请问上述两个语句,哪个语句执行的速度快
					答案:B快

			位运算的现实意义:
				通过位运算符我们可以对数据的操作精确到每一位
			-------------------------------------------------------------
			#include <stdio.h>
			int main(void)
			{
				int i = 5;
				int j = 7;
				int k;

				k = i & j;     //表示按位与
				printf("%d\n",k);    //这里的结果是5
				k = i && j;        //K的值只能是1或者0,因为&&是个逻辑运算符,
								//逻辑运算符的结果只能是真或假,真用1表示,假用0表示	   
				printf("%d\n",k);   //这里的结果是1
				return 0;
			}
			解析:
			5的二进制码为:0101
			7的二进制码为:0111
			两个二进制码进行与运算的结果为:0101
			所以第一个printf的结果是5
			----------------------------------------------------------------------------
			#include <stdio.h>
			int main(void)
			{
				int i = 3;
				int j = 5;
				int k;

				k = i|j;
				printf("%d\n",k);

				k = ~i;   //
				printf("%d\n",k);  //k的值为4

				k = i << i;
				printf("%d\n",k);  //k的值为6
				return 0;
			}
			3的二进制码为:0011
			5的二进制码为:0101
			两个二进制码进行或运算的结果为:0111 即为7
			最终k的值为7
			----------------------------------------------------------------
【NULL】
			C语言中二进制全部为零的含义:
			1.数值零
			2.字符串结束标记符‘\0’
			3.空指针NULL
				NULL表示的是零,而这个零不代表数字零,而表示的是内存单元的编号零.

			根据解码的不同而结果不同

			计算机规定了,以零为编号的存储单元的内容不可读,不可写
			--------------------------------------------------------

【链表】
		算法:
			通俗的定义:
				解题的方法和步骤
			狭义的定义:
				对存储数据的操作
				对不同的存储结果,要完成某一个功能所执行的操作是不一样的
				比如:
					要输出数组中所有的元素的操作和
					要输出链表中所有的元素的操作肯定是不一样的
				这说明:
					算法是依附于存储结构的
					不同的存储结构,所执行的算法是不一样的
			广义的定义:
				广义的算法也叫泛型
				无论数据是如何存储的,对数据的操作都是一样的

		至少可以通过两种结构来存储数据:
			数组
				缺点:
					需要一个连续的很大的内存
					插入和删除元素的效率很低
				优点:
					存取速度快
			链表
				专业术语;
					首节点
						存放第一个有效数据的节点
					尾节点
						存放最后一个有效数据的节点
					头结点
						头结点的数据类型和首节点的类型是一模一样的
						头结点是首节点前面的那个节点
						头结点并不存放有效数据
						设置头结点的目的是为了方便对链表的操作
					头指针
						存放头结点地址的指针变量

					确定一个链表需要一个参数
						头指针

				优点:
					插入删除元素效率高
					不需要一个连续的很大的内存
				缺点:
					查找某个位置的元素效率低
				-----------------------------------------------------------------------------
				#include <stdio.h>
				#include <malloc.h>
				#include <stdlib.h>
				struct Node
				{
				        int data;  //数据域
				        struct Node *pNext;  //指针域
				};

				struct Node *create_list(void);  //函数声明
				#include <stdio.h>
				#include <malloc.h>
				#include <stdlib.h>
				struct Node
				{
				        int data;  //数据域
				        struct Node *pNext;  //指针域
				};

				struct Node *create_list(void);  //函数声明
				void traverser_list(struct Node *);
				int main(void)
				{
				        struct Node *pHead = NULL;
				        pHead = create_list(); //创建一个非循环单链表,且将链表头结点地址赋给pHead
				                                //然后主函数就可以通过pHead确定这个新建链表
				        traverser_list(pHead); //输出链表中的每个元素   

				        return 0;
				}

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

				        struct Node *pHead = (struct Node *)malloc(sizeof(struct Node));
				        if (NULL == pHead)
				        {
				                printf("分配失败,程序终止!\n");
				                exit(-1);
				        }
				        struct Node *pTail = pHead;
				        pTail->pNext = NULL;  //等价于(*pTail).pNext
				        
				        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 empty_list(struct Node *pHead)
				{
				        if(pHead->pNext == NULL;)
				                return true;
				        else
				                return false;
				}
				void traverser_list(struct Node *pHead)
				{
				        struct Node *p = pHead->pNext;
				        while(NULL != p)
				        {
				                printf("%d\n",p->data);
				                p = p->pNext;
				        }
				        return;
				}
				-------------------------------------------------------------------------------------

### 补码与原码的定义 在计算机系统中,数值的表示通常采用二进制形式。为了表示带符号整数(正数和负数),引入了**原码、反码和补码**等概念。 #### 原码 原码是最直观的表示方法,其中最高位是符号位,0 表示正数,1 表示负数,其余位表示数值部分。例如,+5 的原码为 `00000101`,-5 的原码为 `10000101`。 #### 补码 补码是一种用于简化加减法运算的编码方式。在补码表示中,符号位也参与运算,从而避免了单独处理符号位带来的复杂性。正数的补码与其原码相同,而负数的补码可以通过其反码(数值位按位取反)末位加 1 得到。[^3] --- ### 原码与补码的关系 1. **正数的原码与补码相同** 对于正数,原码和补码的表示完全一致。例如,+5 的原码为 `00000101`,补码也为 `00000101`。 2. **负数的补码转换方法** 负数的补码可以通过以下步骤获得: - 首先,将原码的数值位按位取反(得到反码)。 - 然后,在反码的末位加 1,得到补码。 例如,-5 的原码为 `10000101`,数值位为 `0000101`。按位取反后得到反码 `1111010`,再末位加 1,得到补码 `1111011`。因此,-5 的补码为 `1111011`。 3. **补码转原码的方法** 补码转换为原码的过程与原码转换为补码的过程相同: - 如果是正数,原码与补码相同。 - 如果是负数,则对补码的数值位按位取反,末位加 1,同时保持符号位不变,即可得到原码。 例如,已知补码为 `1111011`,数值位为 `111011`。按位取反后得到 `000100`,末位加 1 后得到 `000101`,即数值部分为 5,符号位为 1,因此原码为 `10000101`。[^1] --- ### 原码与补码的优缺点 1. **原码的优点** - 表示直观,易于理解。 - 符号位与数值部分分离,便于人脑识别。 2. **原码的缺点** - 在计算机中进行加减法运算时,需要额外的逻辑来判断符号位,导致电路设计复杂化。 - 存在两个零:+0 和 -0(分别为 `00000000` 和 `10000000`),这会导致一些计算错误。[^2] 3. **补码的优点** - 符号位参与运算,简化了硬件设计。 - 消除了 +0 和 -0 的歧义,只有一个零(`00000000`)。 - 支持直接使用加法器进行减法运算(通过加负数的补码实现)。[^3] 4. **补码的缺点** - 补码的表示方式较为抽象,不易于人脑直接理解。 --- ### 示例代码:原码与补码转换 以下是一个简单的 Python 函数,用于将一个整数转换为其对应的原码和补码表示: ```python def int_to_binary(n, bits=8): """ 将整数 n 转换为指定位数的二进制字符串(补码表示) """ if n >= 0: return format(n, '0{}b'.format(bits)) else: # 计算补码 return format((1 << bits) + n, '0{}b'.format(bits)) def binary_to_int(binary_str): """ 将二进制字符串(补码表示)转换为整数 """ bits = len(binary_str) val = int(binary_str, 2) if binary_str[0] == '1': # 如果是负数 val -= (1 << bits) return val # 示例:将 -5 转换为补码 print("补码表示:", int_to_binary(-5)) # 输出: 11111011 # 示例:将补码转换回整数 print("整数表示:", binary_to_int("11111011")) # 输出: -5 ``` --- ### 总结 原码和补码是计算机中表示带符号整数的两种重要方式。原码直观但不利于硬件实现,而补码虽然抽象但能有效简化加减法运算。在实际应用中,计算机普遍采用补码表示整数,以提高运算效率并简化硬件设计。[^1] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值