一维数据结构,即线性数据结构,包括了数组和链表;
数组
数组的特性
-
存储在屋里空间上的连续的
-
底层的数组长度是不可变的。如果一个长度为8的数组,添加第9个元素时,js引擎会向操作系统申请一个新的连续的更长的空间,再将前8位复制,并添加第9位。所以数组长度变化会消耗性能。
-
数组的变量,指向了数组第一个元素的位置;所有a[1]、a[2]其中的方括号标识存储地址的偏移;操作系统中,通过偏移查询数据性能最好。因此得出数组的
优点:查询性能好;
缺点:
- 因为空间必须是连续的,所以如果数组比较大,当系统的空间碎片较多的时候,容易存不下;空间碎片即指小的不连续的空间;
- 因为数组的长度是固定的,所以数组的内容添加删除时比较消耗性能;
链表
传递链表时,必须传递根节点。而每一个链表的节点,都认为自己是根节点;因为每一个节点都知道自己的指向,而不知道自己的被指向
链表的特性
1、 在空间上不是连续的;
2、 没存放一个值,都要多开销一个引用空间;
优点:
- 只要内存空间足够大,就能存的下,不用担心空间碎片的问题
- 链表的添加和删除非常的容易
缺点:
- 查询某个某个位置的速度慢
- 链表每一个节点都需要创建一个指向next的引用,浪费一些空间。当节点内数据越多的时候,这部分多开销的内存越少。
怎么创建链表?
function Node(value){
this.value = value;
this.next = null;
}
var a = new Node(1);
var b = new Node(2);
var c = new Node(3);
var d = new Node(4);
a.next = b;
b.next = c;
c.next = d;
d.next = null;
线性数据结构的遍历
遍历:将一个集合中的每一个元素进行获取并查看
数组遍历:
function bian (arr){
if(arr === null)return; // 算法中必须有严谨性判断,不允许出现报错;
for(var i = 0;i<arr.length;i++){
console.log(arr[i])
}
}
链表的循环遍历:
function Node(value){
this.value = value;
this.next = null;
}
var Node1 = new Node(1);
var Node2 = new Node(2);
var Node3 = new Node(3);
var Node4 = new Node(4);
Node1.next = Node2;
Node2.next = Node3;
Node3.next = Node4;
function bianLink(root){
var temo = root;
while(true){
if(temp != null){
console.log(temp.value)
}else{
break;
}
temp = temp.next
}
}
链表的递归遍历
function Node(value){
this.value = value;
this.next = null;
}
var Node1 = new Node(1);
var Node2 = new Node(2);
var Node3 = new Node(3);
var Node4 = new Node(4);
Node1.next = Node2;
Node2.next = Node3;
Node3.next = Node4;
// 递归遍历,必须有出口;
function bianLink(root){
if(root === null)return;
console.log(root.value);
bianLink(root.next);
}
链表的逆置
链表的逆置,必须先找到最后一个节点,将其的next从null指向上一个节点,将上一个节点的next指向null;依次循环,直指根节点指向null
function Node(value){
this.value = value;
this.next = null;
}
var Node1 = new Node(1);
var Node2 = new Node(2);
var Node3 = new Node(3);
var Node4 = new Node(4);
Node1.next = Node2;
Node2.next = Node3;
Node3.next = Node4;
Node4.next = null;
function nizhi(root){
if(root.next.next == null){ // 如果当前是倒数第二个节点
root.next.next = root; // 将最后一个节点指向自己
return root.next;
}else{ // 其他情况
var res = nizhi(root.next)
root.next.next = root; // 将下一个节点的next指向自己
root.next = null; // 将自己指向空
return res;
}
}
const newRoot = nizhi(Node2)
console.log(newRoot)
function bianLink(root){
if(root == null) return;
console.log(root.value);
bianLink(root.next)
}
bianLink(newRoot)
冒泡排序
// 冒泡排序
const arr = [4, 5, 21, 4, 8, 4, 2, 3, 0, 6, 3, 211, 9]
// 排序的本质是比较和交换
function compare(a, b) { //比较之后得出是否需要交换
if (a > b) {
return true
} else {
return false
}
}
function exchange(arr, a, b) { // 将数组中ab位置的值进行交换
var temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
function bubbleSort() {
for (var j = 0; j < arr.length; j++) {
for (var i = 0; i < arr.length -1- j; i++) {
if (compare(arr[i], arr[i + 1])) {
exchange(arr, i, i + 1)
}
}
}
}
bubbleSort(arr)
console.log(arr)
选择排序
function selectSort(arr) {
for (var i = 0; i < arr.length; i++) {
var maxIndex = 0;
for (var j = 0; j < arr.length - i; j++) {
if (compare(arr[maxIndex],arr[j])) {
maxIndex = j;
}
}
exchange(arr,maxIndex, arr.length - 1 - i)
}
}
selectSort(arr)
console.log(arr)
快速排序
function quickSort(arr, begin, end) {
if (begin >= end - 1) { // 已经为有序数组
return;
}
var left = begin; // 左指针
var right = end; // 右指针
do {
do { left++ } while (arr[left] < arr[begin] && left < right); // 左指针自增,直到指针位置数值大于等于begin位置数值
do { right-- } while (arr[right] > arr[begin] && left < right); // 右指针自减,直到指针位置数值小于等于begin位置数值
if (left < right) {
exchange(arr, left, right) // 交换左右指针位置数值
}
} while (left < right)
var exchangePoint = left === right ? right - 1 : right;
exchange(arr, begin, exchangePoint)
quickSort(arr, begin, exchangePoint)
quickSort(arr, exchangePoint + 1, end)
}
quickSort(arr, 0, arr.length)
console.log(arr)