周记(8.2~8.8)

任务:

  • 学习JSON、原生AJAX
  • 了解web存储机制
  • 用js实现多功能轮播图
  • 学习双链表、循环单链表的插入、删除、遍历、修改

JSON基础与使用

JSON 是一种轻量级的数据交换格式,是用于存储和传输数据的格式,通常用于服务端向网页传递数据 。

JSON的优点:
容易阅读和编写。
方便机器解析和生成。
采用独立于程序语言的文本格式,但是也使用了常用编程语言的习惯。这些特性使JSON成为理想的数据交换语言。

JSON的两种数据结构

  1. 对象结构(无序)
    对象结构是使用大括号{}括起来的,大括号内是由0个或多个用英文逗号分隔的名称 ⁄ 值对构成的。例:
var jsonObj =
{
    "键名1":1,
    "键名2":2,
    ……
    "键名n":值n
}
//键名是字符串,值可以是数值、字符串、对象、数组或逻辑true和false。
  1. 数组结构(有序)
    JSON数组结构是用中括号[]括起来,中括号内部由0个或多个以英文逗号,分隔的值列表组成。例:
var arr =
[
    {
        "键名1":1,
        "键名2":2
    },
    {
        "键名3":3,
        "键名4":4
    },
    ……
]
//在JSON数组中,每一对“{}”相当于一个JSON对象
//键名是字符串,值可以是数值、字符串、对象、数组或逻辑true和false。

JSON值的数据类型

  1. 数值

JavaScript 中的双精度浮点型格式,取决于实现。
不能使用八进制和十六进制格式。
在数字中不能使用 NaNInfinity

数字类型:

  • 整形(Integer): 数字1-9,0和正负数
  • 分数(Fraction) : 分数,比如 .3,.9
  • 指数(Exponent): 指数,比如 e,e+,e-,E,E+,E-

语法:

var json-object-name = { string : number_value, .......}
//例:var obj = {marks: 97}
  1. 字符串

零个或多个双引号包裹的 Unicode 字符以及反斜杠转义序列。
字符就是只有一个字符的字符串,长度为 1。

如:
在这里插入图片描述
语法:

var json-object-name = { string : "string value", .......}
//例 var obj = {name: 'Amit'}
  1. 布尔值truefalse 两个值
    语法:
var json-object-name = { string : true/false, .......}
//例 var obj = {name: 'Amit', marks: 97, distinction: true}
  1. 空格
    可以在任意一对符号之间插入。可以添加用来让代码更可读。下面的例子展示了使用空格和不使用空格的声明:

语法:

{string:"   ",....}
// var i= "   sachin"; 使用空格
// var j = "  saurav"  不使用空格
  1. null
    意味着空类型。
    语法:
null
// var i = null;

转换为 JS对象

使用内建的 JavaScript eval() 用方法解析JSON数据来生成原生的Javascript对象。eval函数利用的是JavaScript的编译器原理,为了保证语法解析正确,需要将文本包围在括号中。例:

<script>  
var txt = '{ "info" : [' +  
'{ "name":"张三" , "sex":"男" },' +  
'{ "name":"小红" , "sex":"女" },' +  
'{ "name":"王五" , "sex":"男" } ]}';  
  
var obj = eval ("(" + txt + ")");  
  
document.getElementById("name").innerHTML=obj.info[0].name   
document.getElementById("sex").innerHTML=obj.info[0].sex   
</script>  

原生AJAX

AJAX是Asynchronous JavaScript and Xml (异步的JavaScript和xml) 的缩写。
异步为它的一个重要特性,即在客户端发起请求之后不需要等待服务器响应,而可以独立的完成其他工作,即在无需重新加载整个页面地基础上实现局部刷新。

XMLHttpRequest对象

实现Ajax需要XMLHttpReques,XMLHttpRequest对象是AJAX中非常重要的对象,所有的AJAX操作都是基于该对象的。
XMLHttpRequest对象用来封装请求报文,我们向服务器发送的请求信息全部都需要封装到该对象中。

XMLHttpRequest在不同版本浏览器获取方式不同,总的来说一共有三种方式:

1 |var xhr = new XMLHttpRequest();	//目前主流浏览器都支持的
2 |var xhr = new ActiveXObject(“Msxml2.XMLHTTP);	//IE6支持的方式
3 |var xhr = new ActiveXObject(“Microsoft.XMLHTTP);	//IE5.5以下支持的方式
  1. XMLHttpRequest对象的方法
  • open(method,url,async):open()用于设置请求的基本信息,接收三个参数。

method:请求的方法:get或post,接收一个字符串
url:请求的地址,接收一个字符串
Assync:发送的请求是否为异步请求,接收一个布尔值。 true 是异步请求 false 不是异步请求(同步请求)

  • send(string) :send()用于将请求发送给服务器,可以接收一个参数

string: 该参数只在发送post请求时需要。
string参数用于设置请求体

  • setRequestHeader(header,value) :用于设置请求头

header:字符串类型,要设置的请求头的名字
value:字符串类型,要设置的请求头的值

  1. XMLHttpRequest对象的属性
  • readyState:描述XMLHttpRequest的状态,一共有五种状态分别对应了五个数字:

0 :请求尚未初始化,open()尚未被调用
1 :服务器连接已建立,send()尚未被调用
2 :请求已接收,服务器尚未响应
3 :请求已处理,正在接收服务器发送的响应
4 :请求已处理完毕,且响应已就绪。

  • status:请求的响应码

200 响应成功
404 页面未找到
500 服务器内部错误

  • onreadystatechange:该属性需要指向一个函数
    该函数会在readyState属性发生改变时被调用

  • responseText:获得字符串形式的响应数据。

  • responseXML(用的比较少):获得 XML 形式的响应数据。

GET请求和POST请求

GET和POST都是向服务器发送的一种请求,只是发送的机制不同。

  1. 使用get请求时,参数在url中显示,而使用post方式,则不会显示出来:
    get请求会将参数跟在url后进行传递
    post请求作为HTTP消息的实体内容发送给web服务器。

  2. 使用get请求发送数据量小,只能传递大约1024字节。post请求发送数据量大,可以达到2M

  3. get请求需注意缓存问题,post请求不需要:
    get方式请求的数据会被浏览器缓存起来,可以从浏览器的历史记录中读取到这些数据,这可能带来安全问题。

双链表

双向链表也叫双链表,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
  
双向链表中各节点包含以下 3 部分信息:

指针域(左链域):用于指向当前节点的直接前驱节点;   
数据域:用于存储数据元素。   
指针域(右链域):用于指向当前节点的直接后继节点;

双向链表结点的定义

//双向链表结点结构体
typedef struct Node
{
    int data;           //数据
    struct Node* prev;  //前驱指针
    struct Node* next;  //后继指针
}Node;

双向链表的创建

同单链表相比,双链表仅是各节点多了一个用于指向直接前驱的指针域。
与单链表不同,双链表创建过程中,每创建一个新节点,都要与其前驱节点建立两次联系,分别是:
  将新节点的 prior 指针指向直接前驱节点;
  将直接前驱节点的 next 指针指向新节点;

Node* create_node(int data)
{
    Node* node = (Node*)malloc(sizeof(Node));//申请内存
    node->data = data;
    node->prev = NULL;
    node->next = NULL;
    return node;
}

双向链表初始化

上面代码定义了双向链表的结构体,但是仅仅是声明了双向链表结构体中的元素,并没有对元素进行初始化,所以在使用双向链表之前需要对其进行初始化,让头结点和尾结点等于NULL,链表长度等于0。

void init_list(DoubleList* list)
{
    list->head = NULL;
    list->tail = NULL;
    list->size = 0;
}

获取头结点

Node* get_head(DoubleList* list)
{
    return list->head;
}

获取尾结点

Node* get_tail(DoubleList* list)
{
    return list->tail;
}

获取链表长度

size_t get_size(DoubleList* list)
{
    return list->size;
}

遍历链表

遍历链表打印链表中所有的元素

void show_list(DoubleList* list)
{
    Node* node = list->head;
    for (int i = 0; i < list->size; ++i)
    {
        printf("%d ", node->data);
        node = node->next;
    }
    printf("\n");
}

插入头结点

需要考虑两种情况:

  • 链表为空,那插入的结点既是头结点,也是尾结点;
  • 链表不为空,将新结点和链表通过前驱指针prev和后继指针next连接起来,并将头结点改为新插入的结点;
//插入头结点
void push_head(DoubleList* list, int data)
{
    Node* new_node = create_node(data);

    //链表为空
    if(list->size == 0)
    {
        //插入的结点既是头结点,也是尾结点
        list->head = new_node;
        list->tail = new_node;
    }
    //链表不为空
    else
    {
        //将新结点和链表通过前驱指针prev和后继指针next连接起来
        new_node->next = list->head;
        list->head->prev = new_node;
        //将头结点改为新插入的结点
        list->head = new_node;
    }
    list->size++;
}

插入尾结点

和插入头结点一样,需要考虑两种情况:

  • 链表为空,那插入的结点既是尾结点,也是头结点;
  • 链表不为空,将新结点和链表通过前驱指针prev和后继指针next连接起来,并将尾结点改为新插入的结点;
//插入尾结点
void push_tail(DoubleList* list, int data)
{
    Node* new_node = create_node(data);

    //链表为空
    if(list->size == 0)
    {
        //插入的结点既是尾结点,也是头结点
        list->tail = new_node;
        list->head = new_node;
    }
    //链表不为空
    else
    {
        //将新结点和链表通过前驱指针prev和后继指针next连接起来
        list->tail->next = new_node;
        new_node->prev = list->tail;
        //将尾结点改为新插入的结点
        list->tail = new_node;
    }
    list->size++;
}

在任意位置插入一个结点

插入前判断插入的位置是否超出链表的范围,排除插入的位置小于0以及大于链表的长度;
插入的位置如果等于0,等同于插入头结点;
插入的位置如果等于链表的长度,等同于插入尾结点;
插入的位置如果小于等于中间位置,那插入的位置更靠近头结点,我们可以从头结点开始往后遍历到插入的前一个位置;
插入的位置如果大于中间位置,那插入的位置更靠近尾结点,我们可以从尾结点开始往前遍历到插入的前一个位置;

bool insert_node(DoubleList* list, int index, int data)
{ 
    //插入的位置超出链表的范围
    if(index <0 || index > list->size)
        return false;
    //插入的位置如果等于0,等同于插入头结点
    if(index == 0)
    {
        push_head(list,data);
        return true;
    }
    //插入的位置如果等于链表的长度,等同于插入尾结点
    else if(index == list->size)
    {
        push_tail(list,data);
        return true;
    }

    Node* tmp = NULL;
    //插入的位置如果小于等于中间位置,那插入的位置更靠近头结点
    //从头结点开始往后遍历到插入的前一个位置
    if(index <= list->size / 2)
    {
        tmp = list->head;
        for(int i=0; i<index-1;i++)
        {
            tmp = tmp->next;
        }
    }
    //插入的位置如果大于中间位置,那插入的位置更靠近尾结点
    //从尾结点开始往前遍历到插入的前一个位置
    else
    {
        tmp = list->tail;
        for (int i = 0; i < list->size - index; ++i)
        {
            tmp = tmp->prev;
        }
    }

    Node* new_node = create_node(data);

    tmp->next->prev = new_node;
    new_node->next = tmp->next;
    tmp->next = new_node;
    new_node->prev = tmp;
    list->size++;
    return true;
}

删除头结点

需要考虑三种情况:

  • 链表为空,不操作,直接返回;
  • 链表只有一个结点,释放该结点的内存,并初始化链表,将链表长度改为0,头结点和尾结点置为NULL;
  • 链表结点大于1,保存头结点,新头结点等于原头结点的下一个结点,然后释放保存的头结点的内存;
//删除头结点
void del_head(DoubleList* list)
{
    if(list->size == 0)
        return;
    if(list->size == 1)
    {
        free(list->head);//释放内存
        init_list(list);
        return;
    }

    Node* tmp = list->head;//保存头结点
    list->head = tmp->next;
    list->head->prev = NULL;
    
    //释放内存
    free(tmp);
    tmp = NULL;
    list->size--;
}

删除尾结点

和删除头结点类似

  • 链表为空,不操作,直接返回;
  • 链表只有一个结点,释放该结点的内存,并初始化链表,将链表长度改为0,头结点和尾结点置为NULL;
  • 链表结点大于1,保存尾结点,新尾结点等于原尾结点的上一个结点,然后释放保存的尾结点的内存;
//删除尾结点
void del_tail(DoubleList* list)
{
    if(list->size == 0)
        return;
    if(list->size == 1)
    {
        free(list->tail);//释放内存
        init_list(list);
        return;
    }

    Node* tmp = list->tail;//保存尾结点
    list->tail = tmp->prev;
    list->tail->next = NULL;

    free(tmp);//释放内存
    tmp = NULL;
    list->size--;
}

删除任意位置结点

与在任意位置插入结点类似:
删除前判断插入的位置是否超出链表的范围,排除删除的位置小于0以及大于链表的长度;
删除的位置如果等于0,等同于删除头结点;
删除的位置如果等于链表的长度,等同于删除尾结点;
删除的位置如果小于中间位置,那删除的位置更靠近头结点,我们可以从头结点开始往后遍历到删除的结点;
删除的位置如果大于等于中间位置,那删除的位置更靠近尾结点,我们可以从尾结点开始往前遍历到删除的结点;

//删除任意位置结点
bool del_node(DoubleList* list, int index)
{
    //判断插入的位置是否超出链表的范围
    if(index < 0 || index > list->size)
        return false;
    //删除的位置如果等于0,等同于删除头结点
    if(index == 0)
    {
        del_head(list);
        return true;
    }
    //删除的位置如果等于链表的长度,等同于删除尾结点
    if(index == list->size)
    {
        del_tail(list);
        return true;
    }

    Node* tmp = NULL;

    //删除的位置如果小于中间位置
    if(index < list->size/2)
    {
        //从头结点开始往后遍历到删除的的结点
        tmp = list->head;
        for (int i = 0; i < index; ++i)
        {
            tmp = tmp->next;
        }
    }
    //删除的位置如果大于等于中间位置
    else
    {
        //从尾结点开始往前遍历到删除的结点
        tmp = list->tail;
        for (int i = 0; i < list->size - index - 1; ++i)
        {
            tmp = tmp->prev;
        }
    }

    tmp->prev->next = tmp->next;
    tmp->next->prev = tmp->prev;
    free(tmp);//释放内存
    tmp = NULL;
    list->size--;
    return true;
}

获取任意节点位置

遍历前判断插入的位置是否超出链表的范围,排除删除的位置小于0以及大于链表的长度;
目标结点的位置如果小于中间位置,那目标结点的位置更靠近头结点,我们可以从头结点开始往后遍历到目标结点;
目标结点的位置如果大于等于中间位置,那目标结点的位置更靠近尾结点,我们可以从尾结点开始往前遍历到目标结点;

//获取任意位置结点
Node* get_node(DoubleList* list, int index)
{
    //判断插入的位置是否超出链表的范围
    if(index < 0 || index > list->size)
        return NULL;
    Node* node = NULL;
    //目标结点的位置如果小于中间位置
    if(index < list->size / 2)
    {
        //从头结点开始往后遍历到目标结点
        node = list->head;
        for(int i =0; i < index ; i++)
        {
            node = node->next;
        }
    }
    //目标结点的位置如果大于等于中间位置
    else
    {
        //从尾结点开始往前遍历到目标结点
        node = list->tail;
        for (int i = 0; i < list->size - index - 1; ++i)
        {
            node = node->prev;
        }
    }
    return node; 
}

获取链表中指定数据所在的第一个结点

Node* find_data(DoubleList* list, int data)
{
    if(list->size == 0)
        return NULL;
    Node* node = list->head;
    while(node)
    {
        if(node->data == data)
            return node;
        node = node->next;
    }
    return NULL;
}

修改链表中指定结点的值

先获取到目标位置的结点,再修改目标结点的值

bool modify_node(DoubleList* list, int index, int data)
{
    Node* node = get_node(list, index);
    if(node)
    {
        node->data = data;
        return true;
    }
    return false;
}

修改链表中指定的第一个数据

先获取目标数据所在的第一个结点,再修改改结点的值

bool modify_data(DoubleList* list, int data, int val)
{
    Node* node = find_data(list, data);
    if(node)
    {
        node->data = val;
        return true;    
    }
    return false;
}

释放链表

当链表不需要再使用时,我们需要将其内存释放。

void free_list(DoubleList* list)
{
    while(list->size)
    {
        Node* tmp = list->head;
        list->head = list->head->next;
        free(tmp);
        tmp = NULL;
        list->size--;
    }
}

循环链表

将单链表中的终端点的指针由空指针改为指向头结点,就使整个单链表形成一个环,这种头尾相接的单链表称为循环单链表,简称循环链表。

定义结构体

typedef struct SqNode
{
	int data;
	struct SqNode* Next;
}SqNode,*Sqlist;

链表初始化

Sqlist Initlist(Sqlist L)
{
	L = (Sqlist)malloc(sizeof(SqNode));
	if (!L)
		return NULL;
	L->Next = L;
	return L;
}

创建循环链表

Sqlist CreateList(Sqlist L)
{
	Sqlist s;
	Sqlist r;
	int Value;
	s = L->Next;
	printf("请输入您要创建的链表,输入999结束创建\n");
	scanf_s("%d", &Value);
	getchar();
	while (Value!=999)
	{
		r = (Sqlist)malloc(sizeof(SqNode));
		if (!r)
		{
			printf("内存分配失败,结束创建\n");
			return L;
		}
		r->data = Value;
		r->Next = s->Next;
		s->Next = r;
		s = r;
		scanf_s("%d", &Value);
		getchar();
	}
	return L;
}

获取链表长度

int LengthList(Sqlist L)
{
	Sqlist s;
	s = L->Next;
	int Length = 0;
	while (s != L)
	{
		s = s->Next;
		Length++;
	}
	return Length;
}

遍历链表

void PrintfList(Sqlist L)
{
	Sqlist s;
	s = L->Next;
	while (s!=L)
	{
		printf("%d\t", s->data);	//遍历并输出
		s = s->Next;
	}
	printf("\n");
}

插入结点

Sqlist InsertList(Sqlist L, int Locate) 
{
	Sqlist s;
	Sqlist r;
	int i=0;
	int Value;
	int Length = LengthList(L);
	s = L;
	if (Locate > Length || Locate < 0)
	{
		printf("您输入的位置超出有效范围\n");
		return NULL;
	}
	while (i<Locate-1 &&s->Next!=L)
	{
		s=s->Next;
		i++;
	}
	r = (Sqlist)malloc(sizeof(SqNode));
	if (!r)
	{
		printf("申请空间失败\n");
		return NULL;
	}
	s;
	printf("请输入您需要插入的数据\n");
	scanf_s("%d", &Value);
	getchar();
	r->data = Value;
	r->Next = s->Next;
	s->Next = r;
	return L;
}

删除结点

Sqlist DeleteList(Sqlist L, int Locate)
{
	Sqlist s=L;
	Sqlist q;
	int Length = 0;
	int i = 0;
	Length = LengthList(L);
	if (Locate > Length || Locate < 0)
	{
		printf("你输入的位置超出范围\n");
		return NULL;
	}
	while (i<Locate-1 && s->Next!=L)
	{
		i++;
		s = s->Next;
	}
	q=s->Next;
	s->Next = s->Next->Next;
	return q;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值