注意:这只是为了学习和改善自己。我知道数组的可用排序方法。我只想尝试降低TCO的基础知识。
目前正在尝试使用递归处理排序算法。但是当我尝试处理大型数据集(+4000个对象)时,我仍然遇到堆栈溢出错误。我试图实施TCO。我对这个概念比较陌生,但我认为我有它的要点。但是,我仍然收到堆栈溢出错误。
const sort = (arr, counter) => {
if (!counter) {
counter = arr.length - 1;
}
for (let n = 1; n <= counter; n++) {
if(arr[n - 1] < arr[n]) {
let placeHolder = arr[n];
arr[n] = arr[n - 1];
arr[n - 1] = placeHolder;
}
}
counter -= 1;
return counter === 0 ? arr : sort(arr, counter);
};
function sortRecursive(arr) {
return sort(arr);
}
更新:
我设法让它工作,但我不太明白为什么。我设法处理100,000次递归没有问题。我不得不移动检查计数器是否已定义的布尔值。但是,我不太明白为什么会这样做。
const sort = (arr, counter) => {
if (!counter) {
counter = arr.length - 1;
}
for (let n = 1; n <= counter; n++) {
if(arr[n - 1] < arr[n]) {
let placeHolder = arr[n];
arr[n] = arr[n - 1];
arr[n - 1] = placeHolder;
}
}
counter -= 1;
if (counter === 0) {
return arr;
} else {
return sort(arr, counter);
}
};
function sortRecursive(arr) {
return sort(arr, arr.length - 1);
}
输出:
let firstArr = [];
let secondArr = [];
for (let x = 0; x < 100000; x++) {
firstArr.push(Math.ceil(Math.random() * 100000));
secondArr.push(Math.ceil(Math.random() * 100000));
}
sortRecursive(firstArr);
//Array[100000]
答案 0 :(得分:2)
正如您可能知道的,尾调用优化是一种编译器技术,它可以允许程序通过不为每个递归调用分配更多内存来无限递归。
Javascript 不目前尾调优化,但语言规范的ES2015标准包括TCO。每次函数在Javascript中调用自身时,都会创建一个新的堆栈帧,分配新的内存,因此最终会耗尽并崩溃。
有一些技术可以避免这种情况,包括trampolines而不使用递归循环。但目前你无法在Javascript中无限递归。
答案 1 :(得分:0)
为什么你需要递归(它永远不会用4000+元素,因为这超过了每个调用堆栈)?你不能这样做:
const sort = (arr) => {
var counter = arr.length;
while(counter-->0){
for (let n = 1; n <= counter; n++) {
if(arr[n - 1] < arr[n]) {
let placeHolder = arr[n];
arr[n] = arr[n - 1];
arr[n - 1] = placeHolder;
}
}
}
return arr;
}
如果你想要种类的递归,你可以使用 qeue 来保持堆栈为空(需要传递一个回调):
setTimeout(sort,0,arr,counter);//instead of sort(arr,counter);
顺便说一句,更容易,更快(因为它原生实现):
arr.sort((a,b)=>a-b);
答案 2 :(得分:0)
您确定您是否正在进行尾调用优化?
这是使用您更新的代码进行的测试。我改变的唯一事情是:
id
以将代码置于严格模式。某些支持TCO的浏览器可能需要严格模式才能使用TCO。import PIL
from PIL import Image, ImageTk
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
root = Tk()
class Window:
def __init__(self, master=None):
tower = PIL.Image.open("Images/island.png")
master.update()
win_width = int(master.winfo_width())
win_height = int(master.winfo_height())
# Resize the image to the constraints of the root window.
tower = tower.resize((win_width, win_height))
tower_tk = ImageTk.PhotoImage(tower)
# Create a label to hold the background image.
canvas = Canvas(master, width=win_width, height=win_height)
canvas.place(x=0, y=0, anchor='nw')
canvas.create_image(0, 0, image=tower_tk, anchor='nw')
canvas.image = tower_tk
frame = Frame(master)
frame.place(x=win_width, y=win_height, anchor='se')
master.update()
w = Label(master, text="Send and receive files easily", anchor='w')
w.config(font=('times', 32))
w.place(x=0, y=0, anchor='nw')
master.title("Bifrost v1.0")
self.img1 = PhotoImage(file="Images/logo.png")
self.img2 = PhotoImage(file="Images/magnifier.png")
frame.grid_columnconfigure(0, weight=1)
sendButton = Button(frame, image=self.img2)
sendButton.grid(row=0, column=1)
sendButton.image = self.img2
receiveButton = Button(frame, image=self.img1)
receiveButton.grid(row=0, column=2)
receiveButton.image = self.img1
menu = Menu(master)
master.config(menu=menu)
file = Menu(menu)
file.add_command(label='Exit', command=self.client_exit)
menu.add_cascade(label='File', menu=file)
edit = Menu(menu)
edit.add_command(label='abcd')
menu.add_cascade(label='Edit', menu=edit)
help = Menu(menu)
help.add_command(label='About Us', command=self.about)
menu.add_cascade(label='Help', menu=help)
def callback():
path = filedialog.askopenfilename()
e.delete(0, END) # Remove current text in entry
e.insert(0, path) # Insert the 'path'
# print path
w = Label(root, text="File Path:")
e = Entry(root, text="")
b = Button(root, text="Browse", fg="#a1dbcd", bg="black", command=callback)
w.pack(side=TOP)
e.pack(side=TOP)
b.pack(side=TOP)
def client_exit(self):
exit()
def about(self):
message = "This is a project developed by Aditi,Sagar and"
message += "Suyash as the final year project."
messagebox.showinfo("Delete Theme", message)
root.resizable(0,0)
#size of the window
root.geometry("700x400")
app = Window(root)
root.mainloop()
以在每次'use strict';
来电时打印调用堆栈。console.trace()
而不是sort()
。在运行代码段之前打开开发人员控制台并观察调用堆栈跟踪。
我在最新版本的Chrome 59.0.3071.109,Firefox 54.0和Edge 15.15063中对此进行了测试。所有这些堆栈跟踪显示每次调用时调用堆栈都在增长,表明没有尾调用优化。
只是为了踢,我还在Chrome中使用Math.floor()
进行了尝试。它运行了很长时间,可能是一分钟左右,然后当堆栈达到大约10257次调用的深度时,堆栈溢出失败。为了进行比较,标准Math.ceil()
在大约5秒内完成。
这是一个很好的article about JavaScript tail call optimization and related topics。该文章提到的一件事是,您可以使用length = 100000
命令行开关和sort( function( a, b ) { return b - a; } )
在node.js中获得TCO。
--harmony_tailcalls
&#13;